diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2022-09-06 10:56:03 +0200 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2022-09-06 10:56:04 +0200 |
commit | 8284bae723f025cb6a8431566757a3854a3c53eb (patch) | |
tree | 91c86c11413d12add21973c46b0a58f72ad103e0 /drivers | |
parent | 2c2d7a67defa198a8b8148dbaddc9e5554efebc8 (diff) | |
parent | 8869fa666a9e6782c3c896c1fa57d65adca23249 (diff) | |
download | linux-8284bae723f025cb6a8431566757a3854a3c53eb.tar.gz linux-8284bae723f025cb6a8431566757a3854a3c53eb.tar.bz2 linux-8284bae723f025cb6a8431566757a3854a3c53eb.zip |
Merge tag 'drm-misc-next-2022-08-20-1' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for v6.1:
UAPI Changes:
Cross-subsystem Changes:
- DMA-buf: documentation updates.
- Assorted small fixes to vga16fb
- Fix fbdev drivers to use the aperture helpers.
- Make removal of conflicting drivers work correctly without fbdev enabled.
Core Changes:
- bridge, scheduler, dp-mst: Assorted small fixes.
- Add more format helpers to fourcc, and use it to replace the cpp usage.
- Add DRM_FORMAT_Cxx, DRM_FORMAT_Rxx (single channel), and DRM_FORMAT_Dxx
("darkness", inverted single channel)
- Add packed AYUV8888 and XYUV8888 formats.
- Assorted documentation updates.
- Rename ttm_bo_init to ttm_bo_init_validate.
- Allow TTM bo's to exist without backing store.
- Convert drm selftests to kunit.
- Add managed init functions for (panel) bridge, crtc, encoder and connector.
- Fix endianness handling in various format conversion helpers.
- Make tests pass on big-endian platforms, and add test for rgb888 -> rgb565
- Move DRM_PLANE_HELPER_NO_SCALING to atomic helpers and rename, so
drm_plane_helper is no longer needed in most drivers.
- Use idr_init_base instead of idr_init.
- Rename FB and GEM CMA helpers to DMA helpers.
- Rework XRGB8888 related conversion helpers, and add drm_fb_blit() that
takes a iosys_map. Make drm_fb_memcpy take an iosys_map too.
- Move edid luminance calculation to core, and use it in i915.
Driver Changes:
- bridge/{adv7511,ti-sn65dsi86,parade-ps8640}, panel/{simple,nt35510,tc358767},
nouveau, sun4i, mipi-dsi, mgag200, bochs, arm, komeda, vmwgfx, pl111:
Assorted small fixes and doc updates.
- vc4: Rework hdmi power up, and depend on PM.
- panel/simple: Add Samsung LTL101AL01.
- ingenic: Add JZ4760(B) support, avoid a modeset when sharpness property
is unchanged, and use the new PM ops.
- Revert some amdgpu commits that cause garbaged graphics when starting
X, and reapply them with the real problem fixed.
- Completely rework vc4 init to use managed helpers.
- Rename via_drv to via_dri1, and move all stuff there only used by the
dri1 implementation in preperation for atomic modeset.
- Use regmap bulk write in ssd130x.
- Power sequence and clock updates to it6505.
- Split panel-sitrox-st7701 init sequence and rework mode programming code.
- virtio: Improve error and edge conditions handling, and convert to use managed
helpers.
- Add Samsung LTL101AL01, B120XAN01.0, R140NWF5 RH, DMT028VGHMCMI-1A T, panels.
- Add generic fbdev support to komeda.
- Split mgag200 modeset handling to make it more model-specific.
- Convert simpledrm to use atomic helpers.
- Improve udl suspend/disconnect handling.
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/f0c71766-61e8-19b7-763a-5fbcdefc633d@linux.intel.com
Diffstat (limited to 'drivers')
449 files changed, 15937 insertions, 14349 deletions
diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c index 3ebec19a8e02..af57799c86ce 100644 --- a/drivers/dma-buf/sync_file.c +++ b/drivers/dma-buf/sync_file.c @@ -132,7 +132,7 @@ EXPORT_SYMBOL(sync_file_get_fence); char *sync_file_get_name(struct sync_file *sync_file, char *buf, int len) { if (sync_file->user_name[0]) { - strlcpy(buf, sync_file->user_name, len); + strscpy(buf, sync_file->user_name, len); } else { struct dma_fence *fence = sync_file->fence; @@ -172,7 +172,7 @@ static struct sync_file *sync_file_merge(const char *name, struct sync_file *a, return NULL; } sync_file->fence = fence; - strlcpy(sync_file->user_name, name, sizeof(sync_file->user_name)); + strscpy(sync_file->user_name, name, sizeof(sync_file->user_name)); return sync_file; } @@ -262,9 +262,9 @@ err_put_fd: static int sync_fill_fence_info(struct dma_fence *fence, struct sync_fence_info *info) { - strlcpy(info->obj_name, fence->ops->get_timeline_name(fence), + strscpy(info->obj_name, fence->ops->get_timeline_name(fence), sizeof(info->obj_name)); - strlcpy(info->driver_name, fence->ops->get_driver_name(fence), + strscpy(info->driver_name, fence->ops->get_driver_name(fence), sizeof(info->driver_name)); info->status = dma_fence_get_status(fence); diff --git a/drivers/firmware/sysfb.c b/drivers/firmware/sysfb.c index 1f276f108cc9..3fd3563d962b 100644 --- a/drivers/firmware/sysfb.c +++ b/drivers/firmware/sysfb.c @@ -94,6 +94,10 @@ static __init int sysfb_init(void) name = "efi-framebuffer"; else if (si->orig_video_isVGA == VIDEO_TYPE_VLFB) name = "vesa-framebuffer"; + else if (si->orig_video_isVGA == VIDEO_TYPE_VGAC) + name = "vga-framebuffer"; + else if (si->orig_video_isVGA == VIDEO_TYPE_EGAC) + name = "ega-framebuffer"; else name = "platform-framebuffer"; diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 6c2256e8474b..0b2ad7212ee6 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -50,10 +50,9 @@ config DRM_DEBUG_MM If in doubt, say "N". -config DRM_DEBUG_SELFTEST - tristate "kselftests for DRM" - depends on DRM - depends on DEBUG_KERNEL +config DRM_KUNIT_TEST + tristate "KUnit tests for DRM" if !KUNIT_ALL_TESTS + depends on DRM && KUNIT select PRIME_NUMBERS select DRM_DISPLAY_DP_HELPER select DRM_DISPLAY_HELPER @@ -61,19 +60,6 @@ config DRM_DEBUG_SELFTEST select DRM_KMS_HELPER select DRM_BUDDY select DRM_EXPORT_FOR_TESTS if m - default n - help - This option provides kernel modules that can be used to run - various selftests on parts of the DRM api. This option is not - useful for distributions or general kernels, but only for kernel - developers working on DRM and associated drivers. - - If in doubt, say "N". - -config DRM_KUNIT_TEST - tristate "KUnit tests for DRM" if !KUNIT_ALL_TESTS - depends on DRM && KUNIT=y - select DRM_KMS_HELPER default KUNIT_ALL_TESTS help This builds unit tests for DRM. This option is not useful for @@ -214,11 +200,11 @@ config DRM_TTM_HELPER help Helpers for ttm-based gem objects -config DRM_GEM_CMA_HELPER +config DRM_GEM_DMA_HELPER tristate depends on DRM help - Choose this if you need the GEM CMA helper functions + Choose this if you need the GEM DMA helper functions config DRM_GEM_SHMEM_HELPER tristate diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index e7af358e6dda..25d0ba310509 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -40,9 +40,9 @@ obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o obj-$(CONFIG_DRM_BUDDY) += drm_buddy.o -drm_cma_helper-y := drm_gem_cma_helper.o -drm_cma_helper-$(CONFIG_DRM_KMS_HELPER) += drm_fb_cma_helper.o -obj-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_cma_helper.o +drm_dma_helper-y := drm_gem_dma_helper.o +drm_dma_helper-$(CONFIG_DRM_KMS_HELPER) += drm_fb_dma_helper.o +obj-$(CONFIG_DRM_GEM_DMA_HELPER) += drm_dma_helper.o drm_shmem_helper-y := drm_gem_shmem_helper.o obj-$(CONFIG_DRM_GEM_SHMEM_HELPER) += drm_shmem_helper.o @@ -75,7 +75,6 @@ obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o # Drivers and the rest # -obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/ obj-$(CONFIG_DRM_KUNIT_TEST) += tests/ obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c index 8ee4e8491f39..afe22f83d4a6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c @@ -848,7 +848,7 @@ void amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr, mgr->adev = adev; mutex_init(&mgr->lock); - idr_init(&mgr->ctx_handles); + idr_init_base(&mgr->ctx_handles, 1); for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) atomic64_set(&mgr->time_spend[i], 0); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 1369c25448dc..77668c3dae5b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -1160,7 +1160,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) } mutex_init(&fpriv->bo_list_lock); - idr_init(&fpriv->bo_list_handles); + idr_init_base(&fpriv->bo_list_handles, 1); amdgpu_ctx_mgr_init(&fpriv->ctx_mgr, adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index d788a00043a5..37322550d750 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -38,7 +38,6 @@ #include <drm/drm_crtc_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> #include <linux/i2c.h> #include <linux/i2c-algo-bit.h> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 4570ad449390..e6a9b9fc9e0b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -591,7 +591,7 @@ int amdgpu_bo_create(struct amdgpu_device *adev, if (!bp->destroy) bp->destroy = &amdgpu_bo_destroy; - r = ttm_bo_init_reserved(&adev->mman.bdev, &bo->tbo, size, bp->type, + r = ttm_bo_init_reserved(&adev->mman.bdev, &bo->tbo, bp->type, &bo->placement, page_align, &ctx, NULL, bp->resv, bp->destroy); if (unlikely(r != 0)) @@ -1309,7 +1309,7 @@ void amdgpu_bo_release_notify(struct ttm_buffer_object *bo) if (bo->base.resv == &bo->base._resv) amdgpu_amdkfd_remove_fence_on_pt_pd_bos(abo); - if (bo->resource->mem_type != TTM_PL_VRAM || + if (!bo->resource || bo->resource->mem_type != TTM_PL_VRAM || !(abo->flags & AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE) || adev->in_suspend || adev->shutdown) return; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 134575a3893c..2e97099808ca 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -471,7 +471,8 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict, adev = amdgpu_ttm_adev(bo->bdev); - if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) { + if (!old_mem || (old_mem->mem_type == TTM_PL_SYSTEM && + bo->ttm == NULL)) { ttm_bo_move_null(bo, new_mem); goto out; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c index 576849e95296..f4b5301ea2a0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c @@ -282,8 +282,8 @@ static int amdgpu_vkms_plane_atomic_check(struct drm_plane *plane, return PTR_ERR(crtc_state); ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, false, true); if (ret != 0) return ret; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 5140d9c2bf3b..19d595321a60 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -88,6 +88,7 @@ #include <drm/drm_vblank.h> #include <drm/drm_audio_component.h> #include <drm/drm_gem_atomic_helper.h> +#include <drm/drm_plane_helper.h> #include "ivsrcid/dcn/irqsrcs_dcn_1_0.h" @@ -2812,15 +2813,12 @@ static struct drm_mode_config_helper_funcs amdgpu_dm_mode_config_helperfuncs = { static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector) { - u32 max_avg, min_cll, max, min, q, r; struct amdgpu_dm_backlight_caps *caps; struct amdgpu_display_manager *dm; struct drm_connector *conn_base; struct amdgpu_device *adev; struct dc_link *link = NULL; - static const u8 pre_computed_values[] = { - 50, 51, 52, 53, 55, 56, 57, 58, 59, 61, 62, 63, 65, 66, 68, 69, - 71, 72, 74, 75, 77, 79, 81, 82, 84, 86, 88, 90, 92, 94, 96, 98}; + struct drm_luminance_range_info *luminance_range; int i; if (!aconnector || !aconnector->dc_link) @@ -2842,8 +2840,6 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector) caps = &dm->backlight_caps[i]; caps->ext_caps = &aconnector->dc_link->dpcd_sink_ext_caps; caps->aux_support = false; - max_avg = conn_base->hdr_sink_metadata.hdmi_type1.max_fall; - min_cll = conn_base->hdr_sink_metadata.hdmi_type1.min_cll; if (caps->ext_caps->bits.oled == 1 /*|| caps->ext_caps->bits.sdr_aux_backlight_control == 1 || @@ -2855,31 +2851,9 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector) else if (amdgpu_backlight == 1) caps->aux_support = true; - /* From the specification (CTA-861-G), for calculating the maximum - * luminance we need to use: - * Luminance = 50*2**(CV/32) - * Where CV is a one-byte value. - * For calculating this expression we may need float point precision; - * to avoid this complexity level, we take advantage that CV is divided - * by a constant. From the Euclids division algorithm, we know that CV - * can be written as: CV = 32*q + r. Next, we replace CV in the - * Luminance expression and get 50*(2**q)*(2**(r/32)), hence we just - * need to pre-compute the value of r/32. For pre-computing the values - * We just used the following Ruby line: - * (0...32).each {|cv| puts (50*2**(cv/32.0)).round} - * The results of the above expressions can be verified at - * pre_computed_values. - */ - q = max_avg >> 5; - r = max_avg % 32; - max = (1 << q) * pre_computed_values[r]; - - // min luminance: maxLum * (CV/255)^2 / 100 - q = DIV_ROUND_CLOSEST(min_cll, 255); - min = max * DIV_ROUND_CLOSEST((q * q), 100); - - caps->aux_max_input_signal = max; - caps->aux_min_input_signal = min; + luminance_range = &conn_base->display_info.luminance_range; + caps->aux_min_input_signal = luminance_range->min_luminance; + caps->aux_max_input_signal = luminance_range->max_luminance; } void amdgpu_dm_update_connector_after_detect( diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c index fca7cf9dbaee..c450dd66d194 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c @@ -1562,7 +1562,7 @@ int dm_drm_plane_get_property(struct drm_plane *plane, static const struct drm_plane_funcs dm_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, - .destroy = drm_primary_helper_destroy, + .destroy = drm_plane_helper_destroy, .reset = dm_drm_plane_reset, .atomic_duplicate_state = dm_drm_plane_duplicate_state, .atomic_destroy_state = dm_drm_plane_destroy_state, diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig index 6e3f1d600541..c1b89274d2a4 100644 --- a/drivers/gpu/drm/arm/Kconfig +++ b/drivers/gpu/drm/arm/Kconfig @@ -6,7 +6,7 @@ config DRM_HDLCD depends on DRM && OF && (ARM || ARM64 || COMPILE_TEST) depends on COMMON_CLK select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER help Choose this option if you have an ARM High Definition Colour LCD controller. @@ -27,7 +27,7 @@ config DRM_MALI_DISPLAY depends on DRM && OF && (ARM || ARM64 || COMPILE_TEST) depends on COMMON_CLK select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select VIDEOMODE_HELPERS help Choose this option if you want to compile the ARM Mali Display diff --git a/drivers/gpu/drm/arm/display/Kconfig b/drivers/gpu/drm/arm/display/Kconfig index e91598b60781..4acc4285a4eb 100644 --- a/drivers/gpu/drm/arm/display/Kconfig +++ b/drivers/gpu/drm/arm/display/Kconfig @@ -4,7 +4,7 @@ config DRM_KOMEDA depends on DRM && OF depends on COMMON_CLK select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select VIDEOMODE_HELPERS help Choose this option if you want to compile the ARM Komeda display diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c index daa1faccd3e7..6c56f5662bc7 100644 --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c @@ -310,8 +310,7 @@ static int d71_reset(struct d71_dev *d71) u32 __iomem *gcu = d71->gcu_addr; int ret; - malidp_write32_mask(gcu, BLK_CONTROL, - GCU_CONTROL_SRST, GCU_CONTROL_SRST); + malidp_write32(gcu, BLK_CONTROL, GCU_CONTROL_SRST); ret = dp_wait_cond(!(malidp_read32(gcu, BLK_CONTROL) & GCU_CONTROL_SRST), 100, 1000, 10000); diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c index 59172acb9738..4cc07d6bb9d8 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c @@ -11,7 +11,6 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_print.h> #include <drm/drm_vblank.h> @@ -235,7 +234,7 @@ void komeda_crtc_handle_event(struct komeda_crtc *kcrtc, crtc->state->event = NULL; drm_crtc_send_vblank_event(crtc, event); } else { - DRM_WARN("CRTC[%d]: FLIP happen but no pending commit.\n", + DRM_WARN("CRTC[%d]: FLIP happened but no pending commit.\n", drm_crtc_index(&kcrtc->base)); } spin_unlock_irqrestore(&crtc->dev->event_lock, flags); @@ -286,7 +285,7 @@ komeda_crtc_atomic_enable(struct drm_crtc *crtc, komeda_crtc_do_flush(crtc, old); } -static void +void komeda_crtc_flush_and_wait_for_flip_done(struct komeda_crtc *kcrtc, struct completion *input_flip_done) { diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c index ba16895690f1..9fce4239d4ad 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c @@ -9,6 +9,7 @@ #include <linux/platform_device.h> #include <linux/component.h> #include <linux/pm_runtime.h> +#include <drm/drm_fb_helper.h> #include <drm/drm_module.h> #include <drm/drm_of.h> #include "komeda_dev.h" @@ -72,6 +73,7 @@ static int komeda_bind(struct device *dev) } dev_set_drvdata(dev, mdrv); + drm_fbdev_generic_setup(&mdrv->kms->base, 32); return 0; diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c index 3c372d2deb0a..df5da5a44755 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c @@ -5,9 +5,9 @@ * */ #include <drm/drm_device.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_gem.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include "komeda_framebuffer.h" @@ -137,7 +137,7 @@ komeda_fb_none_afbc_size_check(struct komeda_dev *mdev, struct komeda_fb *kfb, } min_size = komeda_fb_get_pixel_addr(kfb, 0, fb->height, i) - - to_drm_gem_cma_obj(obj)->paddr; + - to_drm_gem_dma_obj(obj)->dma_addr; if (obj->size < min_size) { DRM_DEBUG_KMS("The fb->obj[%d] size: 0x%zx lower than the minimum requirement: 0x%llx.\n", i, obj->size, min_size); @@ -239,7 +239,7 @@ dma_addr_t komeda_fb_get_pixel_addr(struct komeda_fb *kfb, int x, int y, int plane) { struct drm_framebuffer *fb = &kfb->base; - const struct drm_gem_cma_object *obj; + const struct drm_gem_dma_object *obj; u32 offset, plane_x, plane_y, block_w, block_sz; if (plane >= fb->format->num_planes) { @@ -247,7 +247,7 @@ komeda_fb_get_pixel_addr(struct komeda_fb *kfb, int x, int y, int plane) return -EINVAL; } - obj = drm_fb_cma_get_gem_obj(fb, plane); + obj = drm_fb_dma_get_gem_obj(fb, plane); offset = fb->offsets[plane]; if (!fb->modifier) { @@ -260,7 +260,7 @@ komeda_fb_get_pixel_addr(struct komeda_fb *kfb, int x, int y, int plane) + plane_y * fb->pitches[plane]; } - return obj->paddr + offset; + return obj->dma_addr + offset; } /* if the fb can be supported by a specific layer */ diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c index 93b7f09b96ca..451746ebbe71 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c @@ -11,7 +11,7 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_managed.h> #include <drm/drm_probe_helper.h> @@ -21,9 +21,9 @@ #include "komeda_framebuffer.h" #include "komeda_kms.h" -DEFINE_DRM_GEM_CMA_FOPS(komeda_cma_fops); +DEFINE_DRM_GEM_DMA_FOPS(komeda_cma_fops); -static int komeda_gem_cma_dumb_create(struct drm_file *file, +static int komeda_gem_dma_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args) { @@ -32,7 +32,7 @@ static int komeda_gem_cma_dumb_create(struct drm_file *file, args->pitch = ALIGN(pitch, mdev->chip.bus_width); - return drm_gem_cma_dumb_create_internal(file, dev, args); + return drm_gem_dma_dumb_create_internal(file, dev, args); } static irqreturn_t komeda_kms_irq_handler(int irq, void *data) @@ -60,7 +60,7 @@ static irqreturn_t komeda_kms_irq_handler(int irq, void *data) static const struct drm_driver komeda_kms_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .lastclose = drm_fb_helper_lastclose, - DRM_GEM_CMA_DRIVER_OPS_WITH_DUMB_CREATE(komeda_gem_cma_dumb_create), + DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(komeda_gem_dma_dumb_create), .fops = &komeda_cma_fops, .name = "komeda", .desc = "Arm Komeda Display Processor driver", @@ -69,6 +69,25 @@ static const struct drm_driver komeda_kms_driver = { .minor = 1, }; +static void komeda_kms_atomic_commit_hw_done(struct drm_atomic_state *state) +{ + struct drm_device *dev = state->dev; + struct komeda_kms_dev *kms = to_kdev(dev); + int i; + + for (i = 0; i < kms->n_crtcs; i++) { + struct komeda_crtc *kcrtc = &kms->crtcs[i]; + + if (kcrtc->base.state->active) { + struct completion *flip_done = NULL; + if (kcrtc->base.state->event) + flip_done = kcrtc->base.state->event->base.completion; + komeda_crtc_flush_and_wait_for_flip_done(kcrtc, flip_done); + } + } + drm_atomic_helper_commit_hw_done(state); +} + static void komeda_kms_commit_tail(struct drm_atomic_state *old_state) { struct drm_device *dev = old_state->dev; @@ -81,7 +100,7 @@ static void komeda_kms_commit_tail(struct drm_atomic_state *old_state) drm_atomic_helper_commit_modeset_enables(dev, old_state); - drm_atomic_helper_commit_hw_done(old_state); + komeda_kms_atomic_commit_hw_done(old_state); drm_atomic_helper_wait_for_flip_done(dev, old_state); diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h index 7889e380ab23..7339339ef6b8 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h @@ -183,6 +183,8 @@ void komeda_kms_cleanup_private_objs(struct komeda_kms_dev *kms); void komeda_crtc_handle_event(struct komeda_crtc *kcrtc, struct komeda_events *evts); +void komeda_crtc_flush_and_wait_for_flip_done(struct komeda_crtc *kcrtc, + struct completion *input_flip_done); struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev); void komeda_kms_detach(struct komeda_kms_dev *kms); diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c index e672b9cffee3..3276a3e82c62 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c @@ -1271,7 +1271,7 @@ int komeda_release_unclaimed_resources(struct komeda_pipeline *pipe, return 0; } -/* Since standalong disabled components must be disabled separately and in the +/* Since standalone disabled components must be disabled separately and in the * last, So a complete disable operation may needs to call pipeline_disable * twice (two phase disabling). * Phase 1: disable the common components, flush it. diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_plane.c b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c index dff22dec54b5..c20ff72f0ae5 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_plane.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c @@ -7,7 +7,6 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_blend.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_print.h> #include "komeda_dev.h" #include "komeda_kms.h" diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c index afc9cd856501..7030339fa232 100644 --- a/drivers/gpu/drm/arm/hdlcd_crtc.c +++ b/drivers/gpu/drm/arm/hdlcd_crtc.c @@ -18,12 +18,11 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_of.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> @@ -252,8 +251,8 @@ static int hdlcd_plane_atomic_check(struct drm_plane *plane, return -EINVAL; return drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, false, true); } @@ -274,7 +273,7 @@ static void hdlcd_plane_atomic_update(struct drm_plane *plane, return; dest_h = drm_rect_height(&new_plane_state->dst); - scanout_start = drm_fb_cma_get_gem_addr(fb, new_plane_state, 0); + scanout_start = drm_fb_dma_get_gem_addr(fb, new_plane_state, 0); hdlcd = plane->dev->dev_private; hdlcd_write(hdlcd, HDLCD_REG_FB_LINE_LENGTH, fb->pitches[0]); diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c index e89ae0ec60eb..a032003c340c 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.c +++ b/drivers/gpu/drm/arm/hdlcd_drv.c @@ -21,13 +21,13 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <drm/drm_aperture.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_debugfs.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_modeset_helper.h> #include <drm/drm_module.h> @@ -40,8 +40,7 @@ static irqreturn_t hdlcd_irq(int irq, void *arg) { - struct drm_device *drm = arg; - struct hdlcd_drm_private *hdlcd = drm->dev_private; + struct hdlcd_drm_private *hdlcd = arg; unsigned long irq_status; irq_status = hdlcd_read(hdlcd, HDLCD_REG_INT_STATUS); @@ -69,61 +68,32 @@ static irqreturn_t hdlcd_irq(int irq, void *arg) return IRQ_HANDLED; } -static void hdlcd_irq_preinstall(struct drm_device *drm) +static int hdlcd_irq_install(struct hdlcd_drm_private *hdlcd) { - struct hdlcd_drm_private *hdlcd = drm->dev_private; + int ret; + /* Ensure interrupts are disabled */ hdlcd_write(hdlcd, HDLCD_REG_INT_MASK, 0); hdlcd_write(hdlcd, HDLCD_REG_INT_CLEAR, ~0); -} - -static void hdlcd_irq_postinstall(struct drm_device *drm) -{ -#ifdef CONFIG_DEBUG_FS - struct hdlcd_drm_private *hdlcd = drm->dev_private; - unsigned long irq_mask = hdlcd_read(hdlcd, HDLCD_REG_INT_MASK); - - /* enable debug interrupts */ - irq_mask |= HDLCD_DEBUG_INT_MASK; - - hdlcd_write(hdlcd, HDLCD_REG_INT_MASK, irq_mask); -#endif -} - -static int hdlcd_irq_install(struct drm_device *drm, int irq) -{ - int ret; - - if (irq == IRQ_NOTCONNECTED) - return -ENOTCONN; - - hdlcd_irq_preinstall(drm); - ret = request_irq(irq, hdlcd_irq, 0, drm->driver->name, drm); + ret = request_irq(hdlcd->irq, hdlcd_irq, 0, "hdlcd", hdlcd); if (ret) return ret; - hdlcd_irq_postinstall(drm); +#ifdef CONFIG_DEBUG_FS + /* enable debug interrupts */ + hdlcd_write(hdlcd, HDLCD_REG_INT_MASK, HDLCD_DEBUG_INT_MASK); +#endif return 0; } -static void hdlcd_irq_uninstall(struct drm_device *drm) +static void hdlcd_irq_uninstall(struct hdlcd_drm_private *hdlcd) { - struct hdlcd_drm_private *hdlcd = drm->dev_private; /* disable all the interrupts that we might have enabled */ - unsigned long irq_mask = hdlcd_read(hdlcd, HDLCD_REG_INT_MASK); - -#ifdef CONFIG_DEBUG_FS - /* disable debug interrupts */ - irq_mask &= ~HDLCD_DEBUG_INT_MASK; -#endif - - /* disable vsync interrupts */ - irq_mask &= ~HDLCD_INTERRUPT_VSYNC; - hdlcd_write(hdlcd, HDLCD_REG_INT_MASK, irq_mask); + hdlcd_write(hdlcd, HDLCD_REG_INT_MASK, 0); - free_irq(hdlcd->irq, drm); + free_irq(hdlcd->irq, hdlcd); } static int hdlcd_load(struct drm_device *drm, unsigned long flags) @@ -183,7 +153,7 @@ static int hdlcd_load(struct drm_device *drm, unsigned long flags) goto irq_fail; hdlcd->irq = ret; - ret = hdlcd_irq_install(drm, hdlcd->irq); + ret = hdlcd_irq_install(hdlcd); if (ret < 0) { DRM_ERROR("failed to install IRQ handler\n"); goto irq_fail; @@ -255,11 +225,11 @@ static void hdlcd_debugfs_init(struct drm_minor *minor) } #endif -DEFINE_DRM_GEM_CMA_FOPS(fops); +DEFINE_DRM_GEM_DMA_FOPS(fops); static const struct drm_driver hdlcd_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, - DRM_GEM_CMA_DRIVER_OPS, + DRM_GEM_DMA_DRIVER_OPS, #ifdef CONFIG_DEBUG_FS .debugfs_init = hdlcd_debugfs_init, #endif @@ -314,6 +284,15 @@ static int hdlcd_drm_bind(struct device *dev) goto err_vblank; } + /* + * If EFI left us running, take over from simple framebuffer + * drivers. Read HDLCD_REG_COMMAND to see if we are enabled. + */ + if (hdlcd_read(hdlcd, HDLCD_REG_COMMAND)) { + hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 0); + drm_aperture_remove_framebuffers(false, &hdlcd_driver); + } + drm_mode_config_reset(drm); drm_kms_helper_poll_init(drm); @@ -335,7 +314,7 @@ err_pm_active: err_unload: of_node_put(hdlcd->crtc.port); hdlcd->crtc.port = NULL; - hdlcd_irq_uninstall(drm); + hdlcd_irq_uninstall(hdlcd); of_reserved_mem_device_release(drm->dev); err_free: drm_mode_config_cleanup(drm); @@ -357,7 +336,7 @@ static void hdlcd_drm_unbind(struct device *dev) hdlcd->crtc.port = NULL; pm_runtime_get_sync(dev); drm_atomic_helper_shutdown(drm); - hdlcd_irq_uninstall(drm); + hdlcd_irq_uninstall(hdlcd); pm_runtime_put(dev); if (pm_runtime_enabled(dev)) pm_runtime_disable(dev); diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index d5aef21426cf..1d0b0c54ccc7 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -19,10 +19,9 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_modeset_helper.h> #include <drm/drm_module.h> @@ -457,7 +456,7 @@ static int malidp_irq_init(struct platform_device *pdev) return 0; } -DEFINE_DRM_GEM_CMA_FOPS(fops); +DEFINE_DRM_GEM_DMA_FOPS(fops); static int malidp_dumb_create(struct drm_file *file_priv, struct drm_device *drm, @@ -469,7 +468,7 @@ static int malidp_dumb_create(struct drm_file *file_priv, args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8), alignment); - return drm_gem_cma_dumb_create_internal(file_priv, drm, args); + return drm_gem_dma_dumb_create_internal(file_priv, drm, args); } #ifdef CONFIG_DEBUG_FS @@ -566,7 +565,7 @@ static void malidp_debugfs_init(struct drm_minor *minor) static const struct drm_driver malidp_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, - DRM_GEM_CMA_DRIVER_OPS_WITH_DUMB_CREATE(malidp_dumb_create), + DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(malidp_dumb_create), #ifdef CONFIG_DEBUG_FS .debugfs_init = malidp_debugfs_init, #endif diff --git a/drivers/gpu/drm/arm/malidp_mw.c b/drivers/gpu/drm/arm/malidp_mw.c index b66ca5b33a7f..ef76d0e6ee2f 100644 --- a/drivers/gpu/drm/arm/malidp_mw.c +++ b/drivers/gpu/drm/arm/malidp_mw.c @@ -10,10 +10,10 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_edid.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_writeback.h> @@ -160,7 +160,7 @@ malidp_mw_encoder_atomic_check(struct drm_encoder *encoder, n_planes = fb->format->num_planes; for (i = 0; i < n_planes; i++) { - struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, i); + struct drm_gem_dma_object *obj = drm_fb_dma_get_gem_obj(fb, i); /* memory write buffers are never rotated */ u8 alignment = malidp_hw_get_pitch_align(malidp->dev, 0); @@ -170,7 +170,7 @@ malidp_mw_encoder_atomic_check(struct drm_encoder *encoder, return -EINVAL; } mw_state->pitches[i] = fb->pitches[i]; - mw_state->addrs[i] = obj->paddr + fb->offsets[i]; + mw_state->addrs[i] = obj->dma_addr + fb->offsets[i]; } mw_state->n_planes = n_planes; diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index 8a9562642d16..45f5e35e7f24 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -13,12 +13,11 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_blend.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_print.h> #include "malidp_hw.h" @@ -334,15 +333,15 @@ static bool malidp_check_pages_threshold(struct malidp_plane_state *ms, for (i = 0; i < ms->n_planes; i++) { struct drm_gem_object *obj; - struct drm_gem_cma_object *cma_obj; + struct drm_gem_dma_object *dma_obj; struct sg_table *sgt; struct scatterlist *sgl; obj = drm_gem_fb_get_obj(ms->base.fb, i); - cma_obj = to_drm_gem_cma_obj(obj); + dma_obj = to_drm_gem_dma_obj(obj); - if (cma_obj->sgt) - sgt = cma_obj->sgt; + if (dma_obj->sgt) + sgt = dma_obj->sgt; else sgt = obj->funcs->get_sg_table(obj); @@ -353,14 +352,14 @@ static bool malidp_check_pages_threshold(struct malidp_plane_state *ms, while (sgl) { if (sgl->length < pgsize) { - if (!cma_obj->sgt) + if (!dma_obj->sgt) kfree(sgt); return false; } sgl = sg_next(sgl); } - if (!cma_obj->sgt) + if (!dma_obj->sgt) kfree(sgt); } @@ -715,7 +714,7 @@ static void malidp_set_plane_base_addr(struct drm_framebuffer *fb, struct malidp_plane *mp, int plane_index) { - dma_addr_t paddr; + dma_addr_t dma_addr; u16 ptr; struct drm_plane *plane = &mp->base; bool afbc = fb->modifier ? true : false; @@ -723,27 +722,27 @@ static void malidp_set_plane_base_addr(struct drm_framebuffer *fb, ptr = mp->layer->ptr + (plane_index << 4); /* - * drm_fb_cma_get_gem_addr() alters the physical base address of the + * drm_fb_dma_get_gem_addr() alters the physical base address of the * framebuffer as per the plane's src_x, src_y co-ordinates (ie to * take care of source cropping). * For AFBC, this is not needed as the cropping is handled by _AD_CROP_H * and _AD_CROP_V registers. */ if (!afbc) { - paddr = drm_fb_cma_get_gem_addr(fb, plane->state, - plane_index); + dma_addr = drm_fb_dma_get_gem_addr(fb, plane->state, + plane_index); } else { - struct drm_gem_cma_object *obj; + struct drm_gem_dma_object *obj; - obj = drm_fb_cma_get_gem_obj(fb, plane_index); + obj = drm_fb_dma_get_gem_obj(fb, plane_index); if (WARN_ON(!obj)) return; - paddr = obj->paddr; + dma_addr = obj->dma_addr; } - malidp_hw_write(mp->hwdev, lower_32_bits(paddr), ptr); - malidp_hw_write(mp->hwdev, upper_32_bits(paddr), ptr + 4); + malidp_hw_write(mp->hwdev, lower_32_bits(dma_addr), ptr); + malidp_hw_write(mp->hwdev, upper_32_bits(dma_addr), ptr + 4); } static void malidp_de_set_plane_afbc(struct drm_plane *plane) diff --git a/drivers/gpu/drm/arm/malidp_regs.h b/drivers/gpu/drm/arm/malidp_regs.h index 514c50dcb74d..3bc16db70ddb 100644 --- a/drivers/gpu/drm/arm/malidp_regs.h +++ b/drivers/gpu/drm/arm/malidp_regs.h @@ -145,7 +145,7 @@ #define MALIDP_SE_COEFFTAB_DATA_MASK 0x3fff #define MALIDP_SE_SET_COEFFTAB_DATA(x) \ ((x) & MALIDP_SE_COEFFTAB_DATA_MASK) -/* Enhance coeffents reigster offset */ +/* Enhance coefficients register offset */ #define MALIDP_SE_IMAGE_ENH 0x3C /* ENH_LIMITS offset 0x0 */ #define MALIDP_SE_ENH_LOW_LEVEL 24 diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index b7bb90ae787f..15dd667aa2e7 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -12,7 +12,6 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> diff --git a/drivers/gpu/drm/armada/armada_gem.c b/drivers/gpu/drm/armada/armada_gem.c index 147abf1a3968..5430265ad458 100644 --- a/drivers/gpu/drm/armada/armada_gem.c +++ b/drivers/gpu/drm/armada/armada_gem.c @@ -107,11 +107,11 @@ armada_gem_linear_back(struct drm_device *dev, struct armada_gem_object *obj) } /* - * We could grab something from CMA if it's enabled, but that + * We could grab something from DMA if it's enabled, but that * involves building in a problem: * - * CMA's interface uses dma_alloc_coherent(), which provides us - * with an CPU virtual address and a device address. + * GEM DMA helper interface uses dma_alloc_coherent(), which provides + * us with an CPU virtual address and a device address. * * The CPU virtual address may be either an address in the kernel * direct mapped region (for example, as it would be on x86) or diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index 424250535fed..f21eb8fb76d8 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -298,12 +298,6 @@ fail: return ret; } -static void armada_ovl_plane_destroy(struct drm_plane *plane) -{ - drm_plane_cleanup(plane); - kfree(plane); -} - static void armada_overlay_reset(struct drm_plane *plane) { struct armada_overlay_state *state; @@ -468,7 +462,7 @@ static int armada_overlay_get_property(struct drm_plane *plane, static const struct drm_plane_funcs armada_ovl_plane_funcs = { .update_plane = armada_overlay_plane_update, .disable_plane = drm_atomic_helper_disable_plane, - .destroy = armada_ovl_plane_destroy, + .destroy = drm_plane_helper_destroy, .reset = armada_overlay_reset, .atomic_duplicate_state = armada_overlay_duplicate_state, .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c index 959d7f0a5108..cc47c032dbc1 100644 --- a/drivers/gpu/drm/armada/armada_plane.c +++ b/drivers/gpu/drm/armada/armada_plane.c @@ -288,7 +288,7 @@ struct drm_plane_state *armada_plane_duplicate_state(struct drm_plane *plane) static const struct drm_plane_funcs armada_primary_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, - .destroy = drm_primary_helper_destroy, + .destroy = drm_plane_helper_destroy, .reset = armada_plane_reset, .atomic_duplicate_state = armada_plane_duplicate_state, .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, diff --git a/drivers/gpu/drm/aspeed/Kconfig b/drivers/gpu/drm/aspeed/Kconfig index 024ccab14f88..8137c39b057b 100644 --- a/drivers/gpu/drm/aspeed/Kconfig +++ b/drivers/gpu/drm/aspeed/Kconfig @@ -5,7 +5,7 @@ config DRM_ASPEED_GFX depends on (COMPILE_TEST || ARCH_ASPEED) depends on MMU select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DMA_CMA if HAVE_DMA_CONTIGUOUS select CMA if HAVE_DMA_CONTIGUOUS select MFD_SYSCON diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c b/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c index f3788d7d82d6..55a3444a51d8 100644 --- a/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c +++ b/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c @@ -7,11 +7,11 @@ #include <drm/drm_crtc_helper.h> #include <drm/drm_device.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_panel.h> #include <drm/drm_simple_kms_helper.h> #include <drm/drm_vblank.h> @@ -168,7 +168,7 @@ static void aspeed_gfx_pipe_update(struct drm_simple_display_pipe *pipe, struct drm_crtc *crtc = &pipe->crtc; struct drm_framebuffer *fb = pipe->plane.state->fb; struct drm_pending_vblank_event *event; - struct drm_gem_cma_object *gem; + struct drm_gem_dma_object *gem; spin_lock_irq(&crtc->dev->event_lock); event = crtc->state->event; @@ -185,10 +185,10 @@ static void aspeed_gfx_pipe_update(struct drm_simple_display_pipe *pipe, if (!fb) return; - gem = drm_fb_cma_get_gem_obj(fb, 0); + gem = drm_fb_dma_get_gem_obj(fb, 0); if (!gem) return; - writel(gem->paddr, priv->base + CRT_ADDR); + writel(gem->dma_addr, priv->base + CRT_ADDR); } static int aspeed_gfx_enable_vblank(struct drm_simple_display_pipe *pipe) diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c index 7780b72de9e8..a94f1a9e8f40 100644 --- a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c +++ b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c @@ -16,9 +16,8 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_device.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_module.h> #include <drm/drm_probe_helper.h> @@ -246,11 +245,11 @@ static void aspeed_gfx_unload(struct drm_device *drm) drm_kms_helper_poll_fini(drm); } -DEFINE_DRM_GEM_CMA_FOPS(fops); +DEFINE_DRM_GEM_DMA_FOPS(fops); static const struct drm_driver aspeed_gfx_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, - DRM_GEM_CMA_DRIVER_OPS, + DRM_GEM_DMA_DRIVER_OPS, .fops = &fops, .name = "aspeed-gfx-drm", .desc = "ASPEED GFX DRM", diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 214b10178454..103bd4fa698b 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -42,7 +42,6 @@ #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_gem_vram_helper.h> #include <drm/drm_managed.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_simple_kms_helper.h> @@ -555,8 +554,8 @@ static int ast_primary_plane_helper_atomic_check(struct drm_plane *plane, new_plane_state->crtc); ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, false, true); if (ret) return ret; @@ -779,8 +778,8 @@ static int ast_cursor_plane_helper_atomic_check(struct drm_plane *plane, new_plane_state->crtc); ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, true, true); if (ret) return ret; diff --git a/drivers/gpu/drm/atmel-hlcdc/Kconfig b/drivers/gpu/drm/atmel-hlcdc/Kconfig index 8ae679f1a518..3bdbab3a6333 100644 --- a/drivers/gpu/drm/atmel-hlcdc/Kconfig +++ b/drivers/gpu/drm/atmel-hlcdc/Kconfig @@ -2,7 +2,7 @@ config DRM_ATMEL_HLCDC tristate "DRM Support for ATMEL HLCDC Display Controller" depends on DRM && OF && COMMON_CLK && MFD_ATMEL_HLCDC && ARM - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_KMS_HELPER select DRM_PANEL help diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 651e3c109360..f7e7f4e919c7 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -20,7 +20,7 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_module.h> #include <drm/drm_probe_helper.h> @@ -730,11 +730,11 @@ static void atmel_hlcdc_dc_unload(struct drm_device *dev) clk_disable_unprepare(dc->hlcdc->periph_clk); } -DEFINE_DRM_GEM_CMA_FOPS(fops); +DEFINE_DRM_GEM_DMA_FOPS(fops); static const struct drm_driver atmel_hlcdc_dc_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, - DRM_GEM_CMA_DRIVER_OPS, + DRM_GEM_DMA_DRIVER_OPS, .fops = &fops, .name = "atmel-hlcdc", .desc = "Atmel HLCD Controller DRM", diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c index 2306ceb3e999..daa508504f47 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c @@ -12,11 +12,10 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_blend.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_cma_helper.h> -#include <drm/drm_plane_helper.h> +#include <drm/drm_gem_dma_helper.h> #include "atmel_hlcdc_dc.h" @@ -449,9 +448,9 @@ static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane, sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR); for (i = 0; i < state->nplanes; i++) { - struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(fb, i); + struct drm_gem_dma_object *gem = drm_fb_dma_get_gem_obj(fb, i); - state->dscrs[i]->addr = gem->paddr + state->offsets[i]; + state->dscrs[i]->addr = gem->dma_addr + state->offsets[i]; atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_PLANE_HEAD(i), diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h index a031a0cd1f18..94de73cbeb2d 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h @@ -394,10 +394,7 @@ void adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1); #else static inline int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511) { - unsigned int offset = adv7511->type == ADV7533 ? - ADV7533_REG_CEC_OFFSET : 0; - - regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset, + regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL, ADV7511_CEC_CTRL_POWER_DOWN); return 0; } diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c b/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c index 0b266f28f150..99964f5a5457 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c @@ -359,7 +359,7 @@ int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511) goto err_cec_alloc; } - regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset, 0); + regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL, 0); /* cec soft reset */ regmap_write(adv7511->regmap_cec, ADV7511_REG_CEC_SOFT_RESET + offset, 0x01); @@ -386,7 +386,7 @@ err_cec_alloc: dev_info(dev, "Initializing CEC failed with error %d, disabling CEC\n", ret); err_cec_parse_dt: - regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset, + regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL, ADV7511_CEC_CTRL_POWER_DOWN); return ret == -EPROBE_DEFER ? ret : 0; } diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 38bf28720f3a..6031bdd92342 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -1340,9 +1340,6 @@ static int adv7511_remove(struct i2c_client *i2c) { struct adv7511 *adv7511 = i2c_get_clientdata(i2c); - i2c_unregister_device(adv7511->i2c_cec); - clk_disable_unprepare(adv7511->cec_clk); - adv7511_uninit_regulators(adv7511); drm_bridge_remove(&adv7511->bridge); @@ -1350,6 +1347,8 @@ static int adv7511_remove(struct i2c_client *i2c) adv7511_audio_exit(adv7511); cec_unregister_adapter(adv7511->cec_adap); + i2c_unregister_device(adv7511->i2c_cec); + clk_disable_unprepare(adv7511->cec_clk); i2c_unregister_device(adv7511->i2c_packet); i2c_unregister_device(adv7511->i2c_edid); diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index d1f1d525aeb6..79fc7a50b497 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -1642,6 +1642,7 @@ static int anx7625_parse_dt(struct device *dev, anx7625_get_swing_setting(dev, pdata); pdata->is_dpi = 0; /* default dsi mode */ + of_node_put(pdata->mipi_host_node); pdata->mipi_host_node = of_graph_get_remote_node(np, 0, 0); if (!pdata->mipi_host_node) { DRM_DEV_ERROR(dev, "fail to get internal panel.\n"); diff --git a/drivers/gpu/drm/bridge/chipone-icn6211.c b/drivers/gpu/drm/bridge/chipone-icn6211.c index 481c86b2406e..b07d2d16c3cf 100644 --- a/drivers/gpu/drm/bridge/chipone-icn6211.c +++ b/drivers/gpu/drm/bridge/chipone-icn6211.c @@ -735,14 +735,12 @@ static int chipone_i2c_probe(struct i2c_client *client, return chipone_dsi_host_attach(icn); } -static int chipone_dsi_remove(struct mipi_dsi_device *dsi) +static void chipone_dsi_remove(struct mipi_dsi_device *dsi) { struct chipone *icn = mipi_dsi_get_drvdata(dsi); mipi_dsi_detach(dsi); drm_bridge_remove(&icn->bridge); - - return 0; } static const struct of_device_id chipone_of_match[] = { diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c index 4b673c4792d7..f9251ec49bf0 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -506,6 +506,9 @@ static int it6505_read(struct it6505 *it6505, unsigned int reg_addr) int err; struct device *dev = &it6505->client->dev; + if (!it6505->powered) + return -ENODEV; + err = regmap_read(it6505->regmap, reg_addr, &value); if (err < 0) { dev_err(dev, "read failed reg[0x%x] err: %d", reg_addr, err); @@ -521,6 +524,9 @@ static int it6505_write(struct it6505 *it6505, unsigned int reg_addr, int err; struct device *dev = &it6505->client->dev; + if (!it6505->powered) + return -ENODEV; + err = regmap_write(it6505->regmap, reg_addr, reg_val); if (err < 0) { @@ -538,6 +544,9 @@ static int it6505_set_bits(struct it6505 *it6505, unsigned int reg, int err; struct device *dev = &it6505->client->dev; + if (!it6505->powered) + return -ENODEV; + err = regmap_update_bits(it6505->regmap, reg, mask, value); if (err < 0) { dev_err(dev, "write reg[0x%x] = 0x%x mask = 0x%x failed err %d", @@ -682,7 +691,7 @@ static void it6505_calc_video_info(struct it6505 *it6505) DRM_DEV_DEBUG_DRIVER(dev, "hactive_start:%d, vactive_start:%d", hdes, vdes); - for (i = 0; i < 10; i++) { + for (i = 0; i < 3; i++) { it6505_set_bits(it6505, REG_DATA_CTRL0, ENABLE_PCLK_COUNTER, ENABLE_PCLK_COUNTER); usleep_range(10000, 15000); @@ -699,7 +708,7 @@ static void it6505_calc_video_info(struct it6505 *it6505) return; } - sum /= 10; + sum /= 3; pclk = 13500 * 2048 / sum; it6505->video_info.clock = pclk; it6505->video_info.hdisplay = hdew; @@ -2341,8 +2350,6 @@ static void it6505_irq_hpd(struct it6505 *it6505) if (!it6505_get_video_status(it6505)) it6505_video_reset(it6505); - - it6505_calc_video_info(it6505); } else { memset(it6505->dpcd, 0, sizeof(it6505->dpcd)); @@ -2559,13 +2566,12 @@ static int it6505_poweron(struct it6505 *it6505) usleep_range(10000, 20000); } + it6505->powered = true; it6505_reset_logic(it6505); it6505_int_mask_enable(it6505); it6505_init(it6505); it6505_lane_off(it6505); - it6505->powered = true; - return 0; } @@ -2945,6 +2951,9 @@ static void it6505_bridge_atomic_enable(struct drm_bridge *bridge, if (ret) dev_err(dev, "Failed to setup AVI infoframe: %d", ret); + it6505_drm_dp_link_set_power(&it6505->aux, &it6505->link, + DP_SET_POWER_D0); + it6505_update_video_parameter(it6505, mode); ret = it6505_send_video_infoframe(it6505, &frame); @@ -3044,7 +3053,7 @@ static int it6505_init_pdata(struct it6505 *it6505) return PTR_ERR(pdata->ovdd); } - pdata->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + pdata->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(pdata->gpiod_reset)) { dev_err(dev, "gpiod_reset gpio not found"); return PTR_ERR(pdata->gpiod_reset); diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c index 8a60e83482a0..5fccacc159f0 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611.c @@ -813,13 +813,14 @@ static int lt9611_connector_init(struct drm_bridge *bridge, struct lt9611 *lt961 drm_connector_helper_add(<9611->connector, <9611_bridge_connector_helper_funcs); - drm_connector_attach_encoder(<9611->connector, bridge->encoder); if (!bridge->encoder) { DRM_ERROR("Parent encoder object not found"); return -ENODEV; } + drm_connector_attach_encoder(<9611->connector, bridge->encoder); + return 0; } diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c index 4277bf4f032b..216af76d0042 100644 --- a/drivers/gpu/drm/bridge/panel.c +++ b/drivers/gpu/drm/bridge/panel.c @@ -8,6 +8,7 @@ #include <drm/drm_bridge.h> #include <drm/drm_connector.h> #include <drm/drm_encoder.h> +#include <drm/drm_managed.h> #include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_of.h> #include <drm/drm_panel.h> @@ -367,6 +368,44 @@ struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev, } EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed); +static void drmm_drm_panel_bridge_release(struct drm_device *drm, void *ptr) +{ + struct drm_bridge *bridge = ptr; + + drm_panel_bridge_remove(bridge); +} + +/** + * drmm_panel_bridge_add - Creates a DRM-managed &drm_bridge and + * &drm_connector that just calls the + * appropriate functions from &drm_panel. + * + * @drm: DRM device to tie the bridge lifetime to + * @panel: The drm_panel being wrapped. Must be non-NULL. + * + * This is the DRM-managed version of drm_panel_bridge_add() which + * automatically calls drm_panel_bridge_remove() when @dev is cleaned + * up. + */ +struct drm_bridge *drmm_panel_bridge_add(struct drm_device *drm, + struct drm_panel *panel) +{ + struct drm_bridge *bridge; + int ret; + + bridge = drm_panel_bridge_add_typed(panel, panel->connector_type); + if (IS_ERR(bridge)) + return bridge; + + ret = drmm_add_action_or_reset(drm, drmm_drm_panel_bridge_release, + bridge); + if (ret) + return ERR_PTR(ret); + + return bridge; +} +EXPORT_SYMBOL(drmm_panel_bridge_add); + /** * drm_panel_bridge_connector - return the connector for the panel bridge * @bridge: The drm_bridge. @@ -420,4 +459,39 @@ struct drm_bridge *devm_drm_of_get_bridge(struct device *dev, return bridge; } EXPORT_SYMBOL(devm_drm_of_get_bridge); + +/** + * drmm_of_get_bridge - Return next bridge in the chain + * @drm: device to tie the bridge lifetime to + * @np: device tree node containing encoder output ports + * @port: port in the device tree node + * @endpoint: endpoint in the device tree node + * + * Given a DT node's port and endpoint number, finds the connected node + * and returns the associated bridge if any, or creates and returns a + * drm panel bridge instance if a panel is connected. + * + * Returns a drmm managed pointer to the bridge if successful, or an error + * pointer otherwise. + */ +struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm, + struct device_node *np, + u32 port, u32 endpoint) +{ + struct drm_bridge *bridge; + struct drm_panel *panel; + int ret; + + ret = drm_of_find_panel_or_bridge(np, port, endpoint, + &panel, &bridge); + if (ret) + return ERR_PTR(ret); + + if (panel) + bridge = drmm_panel_bridge_add(drm, panel); + + return bridge; +} +EXPORT_SYMBOL(drmm_of_get_bridge); + #endif diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c index 31e88cb39f8a..49107a6cdac1 100644 --- a/drivers/gpu/drm/bridge/parade-ps8640.c +++ b/drivers/gpu/drm/bridge/parade-ps8640.c @@ -631,8 +631,8 @@ static int ps8640_probe(struct i2c_client *client) if (!ps_bridge) return -ENOMEM; - ps_bridge->supplies[0].supply = "vdd33"; - ps_bridge->supplies[1].supply = "vdd12"; + ps_bridge->supplies[0].supply = "vdd12"; + ps_bridge->supplies[1].supply = "vdd33"; ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies), ps_bridge->supplies); if (ret) diff --git a/drivers/gpu/drm/bridge/tc358762.c b/drivers/gpu/drm/bridge/tc358762.c index 40439da4db49..7f4fce1aa998 100644 --- a/drivers/gpu/drm/bridge/tc358762.c +++ b/drivers/gpu/drm/bridge/tc358762.c @@ -241,14 +241,12 @@ static int tc358762_probe(struct mipi_dsi_device *dsi) return ret; } -static int tc358762_remove(struct mipi_dsi_device *dsi) +static void tc358762_remove(struct mipi_dsi_device *dsi) { struct tc358762 *ctx = mipi_dsi_get_drvdata(dsi); mipi_dsi_detach(dsi); drm_bridge_remove(&ctx->bridge); - - return 0; } static const struct of_device_id tc358762_of_match[] = { diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c index fdfb14aca926..53259c12d777 100644 --- a/drivers/gpu/drm/bridge/tc358764.c +++ b/drivers/gpu/drm/bridge/tc358764.c @@ -381,14 +381,12 @@ static int tc358764_probe(struct mipi_dsi_device *dsi) return ret; } -static int tc358764_remove(struct mipi_dsi_device *dsi) +static void tc358764_remove(struct mipi_dsi_device *dsi) { struct tc358764 *ctx = mipi_dsi_get_drvdata(dsi); mipi_dsi_detach(dsi); drm_bridge_remove(&ctx->bridge); - - return 0; } static const struct of_device_id tc358764_of_match[] = { diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 02bd757a8987..baaed4d37911 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -889,6 +889,7 @@ static int tc_set_edp_video_mode(struct tc_data *tc, u32 dp0_syncval; u32 bits_per_pixel = 24; u32 in_bw, out_bw; + u32 dpipxlfmt; /* * Recommended maximum number of symbols transferred in a transfer unit: @@ -938,10 +939,15 @@ static int tc_set_edp_video_mode(struct tc_data *tc, if (ret) return ret; - ret = regmap_write(tc->regmap, DPIPXLFMT, - VS_POL_ACTIVE_LOW | HS_POL_ACTIVE_LOW | - DE_POL_ACTIVE_HIGH | SUB_CFG_TYPE_CONFIG1 | - DPI_BPP_RGB888); + dpipxlfmt = DE_POL_ACTIVE_HIGH | SUB_CFG_TYPE_CONFIG1 | DPI_BPP_RGB888; + + if (mode->flags & DRM_MODE_FLAG_NVSYNC) + dpipxlfmt |= VS_POL_ACTIVE_LOW; + + if (mode->flags & DRM_MODE_FLAG_NHSYNC) + dpipxlfmt |= HS_POL_ACTIVE_LOW; + + ret = regmap_write(tc->regmap, DPIPXLFMT, dpipxlfmt); if (ret) return ret; @@ -1244,7 +1250,13 @@ static int tc_main_link_disable(struct tc_data *tc) if (ret) return ret; - return regmap_write(tc->regmap, DP0CTL, 0); + ret = regmap_write(tc->regmap, DP0CTL, 0); + if (ret) + return ret; + + return regmap_update_bits(tc->regmap, DP_PHY_CTRL, + PHY_M0_RST | PHY_M1_RST | PHY_M0_EN, + PHY_M0_RST | PHY_M1_RST); } static int tc_dsi_rx_enable(struct tc_data *tc) @@ -1252,10 +1264,10 @@ static int tc_dsi_rx_enable(struct tc_data *tc) u32 value; int ret; - regmap_write(tc->regmap, PPI_D0S_CLRSIPOCOUNT, 3); - regmap_write(tc->regmap, PPI_D1S_CLRSIPOCOUNT, 3); - regmap_write(tc->regmap, PPI_D2S_CLRSIPOCOUNT, 3); - regmap_write(tc->regmap, PPI_D3S_CLRSIPOCOUNT, 3); + regmap_write(tc->regmap, PPI_D0S_CLRSIPOCOUNT, 5); + regmap_write(tc->regmap, PPI_D1S_CLRSIPOCOUNT, 5); + regmap_write(tc->regmap, PPI_D2S_CLRSIPOCOUNT, 5); + regmap_write(tc->regmap, PPI_D3S_CLRSIPOCOUNT, 5); regmap_write(tc->regmap, PPI_D0S_ATMR, 0); regmap_write(tc->regmap, PPI_D1S_ATMR, 0); regmap_write(tc->regmap, PPI_TX_RX_TA, TTA_GET | TTA_SURE); @@ -1496,41 +1508,16 @@ tc_edp_bridge_atomic_disable(struct drm_bridge *bridge, dev_err(tc->dev, "main link disable error: %d\n", ret); } -static bool tc_bridge_mode_fixup(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - struct drm_display_mode *adj) -{ - /* Fixup sync polarities, both hsync and vsync are active low */ - adj->flags = mode->flags; - adj->flags |= (DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC); - adj->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC); - - return true; -} - -static int tc_common_atomic_check(struct drm_bridge *bridge, - struct drm_bridge_state *bridge_state, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state, - const unsigned int max_khz) -{ - tc_bridge_mode_fixup(bridge, &crtc_state->mode, - &crtc_state->adjusted_mode); - - if (crtc_state->adjusted_mode.clock > max_khz) - return -EINVAL; - - return 0; -} - static int tc_dpi_atomic_check(struct drm_bridge *bridge, struct drm_bridge_state *bridge_state, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { /* DSI->DPI interface clock limitation: upto 100 MHz */ - return tc_common_atomic_check(bridge, bridge_state, crtc_state, - conn_state, 100000); + if (crtc_state->adjusted_mode.clock > 100000) + return -EINVAL; + + return 0; } static int tc_edp_atomic_check(struct drm_bridge *bridge, @@ -1539,8 +1526,10 @@ static int tc_edp_atomic_check(struct drm_bridge *bridge, struct drm_connector_state *conn_state) { /* DPI->(e)DP interface clock limitation: upto 154 MHz */ - return tc_common_atomic_check(bridge, bridge_state, crtc_state, - conn_state, 154000); + if (crtc_state->adjusted_mode.clock > 154000) + return -EINVAL; + + return 0; } static enum drm_mode_status @@ -1783,7 +1772,6 @@ static const struct drm_bridge_funcs tc_edp_bridge_funcs = { .atomic_check = tc_edp_atomic_check, .atomic_enable = tc_edp_bridge_atomic_enable, .atomic_disable = tc_edp_bridge_atomic_disable, - .mode_fixup = tc_bridge_mode_fixup, .detect = tc_bridge_detect, .get_edid = tc_get_edid, .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, @@ -2010,9 +1998,10 @@ static int tc_probe_bridge_endpoint(struct tc_data *tc) for_each_endpoint_of_node(dev->of_node, node) { of_graph_parse_endpoint(node, &endpoint); - if (endpoint.port > 2) + if (endpoint.port > 2) { + of_node_put(node); return -EINVAL; - + } mode |= BIT(endpoint.port); } diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index d6dd4d99a229..90bbabde1595 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -698,11 +698,6 @@ static int ti_sn_bridge_attach(struct drm_bridge *bridge, struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge); int ret; - if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { - DRM_ERROR("Fix bridge driver to make connector optional!"); - return -EINVAL; - } - pdata->aux.drm_dev = bridge->dev; ret = drm_dp_aux_register(&pdata->aux); if (ret < 0) { @@ -710,15 +705,18 @@ static int ti_sn_bridge_attach(struct drm_bridge *bridge, return ret; } - /* We never want the next bridge to *also* create a connector: */ - flags |= DRM_BRIDGE_ATTACH_NO_CONNECTOR; - - /* Attach the next bridge */ + /* + * Attach the next bridge. + * We never want the next bridge to *also* create a connector. + */ ret = drm_bridge_attach(bridge->encoder, pdata->next_bridge, - &pdata->bridge, flags); + &pdata->bridge, flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR); if (ret < 0) goto err_initted_aux; + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) + return 0; + pdata->connector = drm_bridge_connector_init(pdata->bridge.dev, pdata->bridge.encoder); if (IS_ERR(pdata->connector)) { @@ -779,9 +777,9 @@ static void ti_sn_bridge_set_dsi_rate(struct ti_sn65dsi86 *pdata) regmap_write(pdata->regmap, SN_DSIA_CLK_FREQ_REG, val); } -static unsigned int ti_sn_bridge_get_bpp(struct ti_sn65dsi86 *pdata) +static unsigned int ti_sn_bridge_get_bpp(struct drm_connector *connector) { - if (pdata->connector->display_info.bpc <= 6) + if (connector->display_info.bpc <= 6) return 18; else return 24; @@ -796,7 +794,7 @@ static const unsigned int ti_sn_bridge_dp_rate_lut[] = { 0, 1620, 2160, 2430, 2700, 3240, 4320, 5400 }; -static int ti_sn_bridge_calc_min_dp_rate_idx(struct ti_sn65dsi86 *pdata) +static int ti_sn_bridge_calc_min_dp_rate_idx(struct ti_sn65dsi86 *pdata, unsigned int bpp) { unsigned int bit_rate_khz, dp_rate_mhz; unsigned int i; @@ -804,7 +802,7 @@ static int ti_sn_bridge_calc_min_dp_rate_idx(struct ti_sn65dsi86 *pdata) &pdata->bridge.encoder->crtc->state->adjusted_mode; /* Calculate minimum bit rate based on our pixel clock. */ - bit_rate_khz = mode->clock * ti_sn_bridge_get_bpp(pdata); + bit_rate_khz = mode->clock * bpp; /* Calculate minimum DP data rate, taking 80% as per DP spec */ dp_rate_mhz = DIV_ROUND_UP(bit_rate_khz * DP_CLK_FUDGE_NUM, @@ -1016,12 +1014,21 @@ static void ti_sn_bridge_atomic_enable(struct drm_bridge *bridge, struct drm_bridge_state *old_bridge_state) { struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge); + struct drm_connector *connector; const char *last_err_str = "No supported DP rate"; unsigned int valid_rates; int dp_rate_idx; unsigned int val; int ret = -EINVAL; int max_dp_lanes; + unsigned int bpp; + + connector = drm_atomic_get_new_connector_for_encoder(old_bridge_state->base.state, + bridge->encoder); + if (!connector) { + dev_err_ratelimited(pdata->dev, "Could not get the connector\n"); + return; + } max_dp_lanes = ti_sn_get_max_lanes(pdata); pdata->dp_lanes = min(pdata->dp_lanes, max_dp_lanes); @@ -1047,8 +1054,9 @@ static void ti_sn_bridge_atomic_enable(struct drm_bridge *bridge, drm_dp_dpcd_writeb(&pdata->aux, DP_EDP_CONFIGURATION_SET, DP_ALTERNATE_SCRAMBLER_RESET_ENABLE); + bpp = ti_sn_bridge_get_bpp(connector); /* Set the DP output format (18 bpp or 24 bpp) */ - val = (ti_sn_bridge_get_bpp(pdata) == 18) ? BPP_18_RGB : 0; + val = bpp == 18 ? BPP_18_RGB : 0; regmap_update_bits(pdata->regmap, SN_DATA_FORMAT_REG, BPP_18_RGB, val); /* DP lane config */ @@ -1059,7 +1067,7 @@ static void ti_sn_bridge_atomic_enable(struct drm_bridge *bridge, valid_rates = ti_sn_bridge_read_valid_rates(pdata); /* Train until we run out of rates */ - for (dp_rate_idx = ti_sn_bridge_calc_min_dp_rate_idx(pdata); + for (dp_rate_idx = ti_sn_bridge_calc_min_dp_rate_idx(pdata, bpp); dp_rate_idx < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut); dp_rate_idx++) { if (!(valid_rates & BIT(dp_rate_idx))) @@ -1198,10 +1206,9 @@ static int ti_sn_bridge_probe(struct auxiliary_device *adev, int ret; pdata->next_bridge = devm_drm_of_get_bridge(pdata->dev, np, 1, 0); - if (IS_ERR(pdata->next_bridge)) { - DRM_ERROR("failed to create panel bridge\n"); - return PTR_ERR(pdata->next_bridge); - } + if (IS_ERR(pdata->next_bridge)) + return dev_err_probe(pdata->dev, PTR_ERR(pdata->next_bridge), + "failed to create panel bridge\n"); ti_sn_bridge_parse_lanes(pdata, np); diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index e5bab236b3ae..32b295003f49 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -1597,7 +1597,7 @@ static int drm_dp_aux_reply_duration(const struct drm_dp_aux_msg *msg) /* * Calculate the length of the i2c transfer in usec, assuming - * the i2c bus speed is as specified. Gives the the "worst" + * the i2c bus speed is as specified. Gives the "worst" * case estimate, ie. successful while as long as possible. * Doesn't account the "MOT" bit, and instead assumes each * message includes a START, ADDRESS and STOP. Neither does it diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index 57e65423e50d..7a94a5288e8d 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -4907,14 +4907,14 @@ void drm_dp_mst_dump_topology(struct seq_file *m, seq_printf(m, "dpcd: %*ph\n", DP_RECEIVER_CAP_SIZE, buf); ret = drm_dp_dpcd_read(mgr->aux, DP_FAUX_CAP, buf, 2); - if (ret) { + if (ret != 2) { seq_printf(m, "faux/mst read failed\n"); goto out; } seq_printf(m, "faux/mst: %*ph\n", 2, buf); ret = drm_dp_dpcd_read(mgr->aux, DP_MSTM_CTRL, buf, 1); - if (ret) { + if (ret != 1) { seq_printf(m, "mst ctrl read failed\n"); goto out; } @@ -4922,7 +4922,7 @@ void drm_dp_mst_dump_topology(struct seq_file *m, /* dump the standard OUI branch header */ ret = drm_dp_dpcd_read(mgr->aux, DP_BRANCH_OUI, buf, DP_BRANCH_OUI_HEADER_SIZE); - if (ret) { + if (ret != DP_BRANCH_OUI_HEADER_SIZE) { seq_printf(m, "branch oui read failed\n"); goto out; } diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 8bf41aa24068..c6abfd3d4b62 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -38,7 +38,6 @@ #include <drm/drm_drv.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_print.h> #include <drm/drm_self_refresh_helper.h> #include <drm/drm_vblank.h> diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c index 6e433d465f41..cf92a9ae8034 100644 --- a/drivers/gpu/drm/drm_auth.c +++ b/drivers/gpu/drm/drm_auth.c @@ -140,14 +140,14 @@ struct drm_master *drm_master_create(struct drm_device *dev) kref_init(&master->refcount); drm_master_legacy_init(master); - idr_init(&master->magic_map); + idr_init_base(&master->magic_map, 1); master->dev = dev; /* initialize the tree of output resource lessees */ INIT_LIST_HEAD(&master->lessees); INIT_LIST_HEAD(&master->lessee_list); idr_init(&master->leases); - idr_init(&master->lessee_idr); + idr_init_base(&master->lessee_idr, 1); return master; } diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 6abf7a2407e9..1545c50fd1c8 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -847,8 +847,8 @@ static int select_bus_fmt_recursive(struct drm_bridge *first_bridge, struct drm_connector_state *conn_state, u32 out_bus_fmt) { + unsigned int i, num_in_bus_fmts = 0; struct drm_bridge_state *cur_state; - unsigned int num_in_bus_fmts, i; struct drm_bridge *prev_bridge; u32 *in_bus_fmts; int ret; @@ -969,7 +969,7 @@ drm_atomic_bridge_chain_select_bus_fmts(struct drm_bridge *bridge, struct drm_connector *conn = conn_state->connector; struct drm_encoder *encoder = bridge->encoder; struct drm_bridge_state *last_bridge_state; - unsigned int i, num_out_bus_fmts; + unsigned int i, num_out_bus_fmts = 0; struct drm_bridge *last_bridge; u32 *out_bus_fmts; int ret = 0; diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c index af3b7395bf69..2b230b4d6942 100644 --- a/drivers/gpu/drm/drm_client.c +++ b/drivers/gpu/drm/drm_client.c @@ -264,7 +264,7 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u dumb_args.width = width; dumb_args.height = height; - dumb_args.bpp = info->cpp[0] * 8; + dumb_args.bpp = drm_format_info_bpp(info, 0); ret = drm_mode_create_dumb(dev, &dumb_args, client->file); if (ret) goto err_delete; @@ -373,7 +373,7 @@ static int drm_client_buffer_addfb(struct drm_client_buffer *buffer, int ret; info = drm_format_info(format); - fb_req.bpp = info->cpp[0] * 8; + fb_req.bpp = drm_format_info_bpp(info, 0); fb_req.depth = info->depth; fb_req.width = width; fb_req.height = height; diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c index 17c6c3eefcd6..d021497841b8 100644 --- a/drivers/gpu/drm/drm_color_mgmt.c +++ b/drivers/gpu/drm/drm_color_mgmt.c @@ -575,7 +575,7 @@ int drm_plane_create_color_properties(struct drm_plane *plane, len++; } - prop = drm_property_create_enum(dev, 0, "COLOR_RANGE", + prop = drm_property_create_enum(dev, 0, "COLOR_RANGE", enum_list, len); if (!prop) return -ENOMEM; diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 1ab083b35e3b..e3142c8142b3 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -22,15 +22,16 @@ #include <drm/drm_auth.h> #include <drm/drm_connector.h> +#include <drm/drm_drv.h> #include <drm/drm_edid.h> #include <drm/drm_encoder.h> +#include <drm/drm_file.h> +#include <drm/drm_managed.h> #include <drm/drm_panel.h> -#include <drm/drm_utils.h> #include <drm/drm_print.h> -#include <drm/drm_drv.h> -#include <drm/drm_file.h> #include <drm/drm_privacy_screen_consumer.h> #include <drm/drm_sysfs.h> +#include <drm/drm_utils.h> #include <linux/fb.h> #include <linux/uaccess.h> @@ -214,23 +215,11 @@ void drm_connector_free_work_fn(struct work_struct *work) } } -/** - * drm_connector_init - Init a preallocated connector - * @dev: DRM device - * @connector: the connector to init - * @funcs: callbacks for this connector - * @connector_type: user visible type of the connector - * - * Initialises a preallocated connector. Connectors should be - * subclassed as part of driver connector objects. - * - * Returns: - * Zero on success, error code on failure. - */ -int drm_connector_init(struct drm_device *dev, - struct drm_connector *connector, - const struct drm_connector_funcs *funcs, - int connector_type) +static int __drm_connector_init(struct drm_device *dev, + struct drm_connector *connector, + const struct drm_connector_funcs *funcs, + int connector_type, + struct i2c_adapter *ddc) { struct drm_mode_config *config = &dev->mode_config; int ret; @@ -278,6 +267,9 @@ int drm_connector_init(struct drm_device *dev, goto out_put_type_id; } + /* provide ddc symlink in sysfs */ + connector->ddc = ddc; + INIT_LIST_HEAD(&connector->global_connector_list_entry); INIT_LIST_HEAD(&connector->probed_modes); INIT_LIST_HEAD(&connector->modes); @@ -334,6 +326,38 @@ out_put: return ret; } + +/** + * drm_connector_init - Init a preallocated connector + * @dev: DRM device + * @connector: the connector to init + * @funcs: callbacks for this connector + * @connector_type: user visible type of the connector + * + * Initialises a preallocated connector. Connectors should be + * subclassed as part of driver connector objects. + * + * At driver unload time the driver's &drm_connector_funcs.destroy hook + * should call drm_connector_cleanup() and free the connector structure. + * The connector structure should not be allocated with devm_kzalloc(). + * + * Note: consider using drmm_connector_init() instead of + * drm_connector_init() to let the DRM managed resource infrastructure + * take care of cleanup and deallocation. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_connector_init(struct drm_device *dev, + struct drm_connector *connector, + const struct drm_connector_funcs *funcs, + int connector_type) +{ + if (drm_WARN_ON(dev, !(funcs && funcs->destroy))) + return -EINVAL; + + return __drm_connector_init(dev, connector, funcs, connector_type, NULL); +} EXPORT_SYMBOL(drm_connector_init); /** @@ -347,8 +371,16 @@ EXPORT_SYMBOL(drm_connector_init); * Initialises a preallocated connector. Connectors should be * subclassed as part of driver connector objects. * + * At driver unload time the driver's &drm_connector_funcs.destroy hook + * should call drm_connector_cleanup() and free the connector structure. + * The connector structure should not be allocated with devm_kzalloc(). + * * Ensures that the ddc field of the connector is correctly set. * + * Note: consider using drmm_connector_init() instead of + * drm_connector_init_with_ddc() to let the DRM managed resource + * infrastructure take care of cleanup and deallocation. + * * Returns: * Zero on success, error code on failure. */ @@ -358,18 +390,63 @@ int drm_connector_init_with_ddc(struct drm_device *dev, int connector_type, struct i2c_adapter *ddc) { + if (drm_WARN_ON(dev, !(funcs && funcs->destroy))) + return -EINVAL; + + return __drm_connector_init(dev, connector, funcs, connector_type, ddc); +} +EXPORT_SYMBOL(drm_connector_init_with_ddc); + +static void drm_connector_cleanup_action(struct drm_device *dev, + void *ptr) +{ + struct drm_connector *connector = ptr; + + drm_connector_cleanup(connector); +} + +/** + * drmm_connector_init - Init a preallocated connector + * @dev: DRM device + * @connector: the connector to init + * @funcs: callbacks for this connector + * @connector_type: user visible type of the connector + * @ddc: optional pointer to the associated ddc adapter + * + * Initialises a preallocated connector. Connectors should be + * subclassed as part of driver connector objects. + * + * Cleanup is automatically handled with a call to + * drm_connector_cleanup() in a DRM-managed action. + * + * The connector structure should be allocated with drmm_kzalloc(). + * + * Returns: + * Zero on success, error code on failure. + */ +int drmm_connector_init(struct drm_device *dev, + struct drm_connector *connector, + const struct drm_connector_funcs *funcs, + int connector_type, + struct i2c_adapter *ddc) +{ int ret; - ret = drm_connector_init(dev, connector, funcs, connector_type); + if (drm_WARN_ON(dev, funcs && funcs->destroy)) + return -EINVAL; + + ret = __drm_connector_init(dev, connector, funcs, connector_type, NULL); if (ret) return ret; - /* provide ddc symlink in sysfs */ - connector->ddc = ddc; + ret = drmm_add_action_or_reset(dev, drm_connector_cleanup_action, + connector); + if (ret) + return ret; - return ret; + return 0; } -EXPORT_SYMBOL(drm_connector_init_with_ddc); +EXPORT_SYMBOL(drmm_connector_init); /** * drm_connector_attach_edid_property - attach edid property. @@ -517,6 +594,9 @@ EXPORT_SYMBOL(drm_connector_cleanup); * e.g. DP MST connectors. All other connectors will be registered automatically * when calling drm_dev_register(). * + * When the connector is no longer available, callers must call + * drm_connector_unregister(). + * * Returns: * Zero on success, error code on failure. */ @@ -573,9 +653,8 @@ EXPORT_SYMBOL(drm_connector_register); * @connector: the connector to unregister * * Unregister userspace interfaces for a connector. Only call this for - * connectors which have registered explicitly by calling drm_dev_register(), - * since connectors are unregistered automatically when drm_dev_unregister() is - * called. + * connectors which have been registered explicitly by calling + * drm_connector_register(). */ void drm_connector_unregister(struct drm_connector *connector) { diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index cad2a7e5166f..df9bf3c9206e 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -343,9 +343,10 @@ static int __drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc * * The @primary and @cursor planes are only relevant for legacy uAPI, see * &drm_crtc.primary and &drm_crtc.cursor. * - * Note: consider using drmm_crtc_alloc_with_planes() instead of - * drm_crtc_init_with_planes() to let the DRM managed resource infrastructure - * take care of cleanup and deallocation. + * Note: consider using drmm_crtc_alloc_with_planes() or + * drmm_crtc_init_with_planes() instead of drm_crtc_init_with_planes() + * to let the DRM managed resource infrastructure take care of cleanup + * and deallocation. * * Returns: * Zero on success, error code on failure. @@ -370,14 +371,88 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, } EXPORT_SYMBOL(drm_crtc_init_with_planes); -static void drmm_crtc_alloc_with_planes_cleanup(struct drm_device *dev, - void *ptr) +static void drmm_crtc_init_with_planes_cleanup(struct drm_device *dev, + void *ptr) { struct drm_crtc *crtc = ptr; drm_crtc_cleanup(crtc); } +__printf(6, 0) +static int __drmm_crtc_init_with_planes(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_plane *primary, + struct drm_plane *cursor, + const struct drm_crtc_funcs *funcs, + const char *name, + va_list args) +{ + int ret; + + drm_WARN_ON(dev, funcs && funcs->destroy); + + ret = __drm_crtc_init_with_planes(dev, crtc, primary, cursor, funcs, + name, args); + if (ret) + return ret; + + ret = drmm_add_action_or_reset(dev, drmm_crtc_init_with_planes_cleanup, + crtc); + if (ret) + return ret; + + return 0; +} + +/** + * drmm_crtc_init_with_planes - Initialise a new CRTC object with + * specified primary and cursor planes. + * @dev: DRM device + * @crtc: CRTC object to init + * @primary: Primary plane for CRTC + * @cursor: Cursor plane for CRTC + * @funcs: callbacks for the new CRTC + * @name: printf style format string for the CRTC name, or NULL for default name + * + * Inits a new object created as base part of a driver crtc object. Drivers + * should use this function instead of drm_crtc_init(), which is only provided + * for backwards compatibility with drivers which do not yet support universal + * planes). For really simple hardware which has only 1 plane look at + * drm_simple_display_pipe_init() instead. + * + * Cleanup is automatically handled through registering + * drmm_crtc_cleanup() with drmm_add_action(). The crtc structure should + * be allocated with drmm_kzalloc(). + * + * The @drm_crtc_funcs.destroy hook must be NULL. + * + * The @primary and @cursor planes are only relevant for legacy uAPI, see + * &drm_crtc.primary and &drm_crtc.cursor. + * + * Returns: + * Zero on success, error code on failure. + */ +int drmm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, + struct drm_plane *primary, + struct drm_plane *cursor, + const struct drm_crtc_funcs *funcs, + const char *name, ...) +{ + va_list ap; + int ret; + + va_start(ap, name); + ret = __drmm_crtc_init_with_planes(dev, crtc, primary, cursor, funcs, + name, ap); + va_end(ap); + if (ret) + return ret; + + return 0; +} +EXPORT_SYMBOL(drmm_crtc_init_with_planes); + void *__drmm_crtc_alloc_with_planes(struct drm_device *dev, size_t size, size_t offset, struct drm_plane *primary, @@ -400,17 +475,12 @@ void *__drmm_crtc_alloc_with_planes(struct drm_device *dev, crtc = container + offset; va_start(ap, name); - ret = __drm_crtc_init_with_planes(dev, crtc, primary, cursor, funcs, - name, ap); + ret = __drmm_crtc_init_with_planes(dev, crtc, primary, cursor, funcs, + name, ap); va_end(ap); if (ret) return ERR_PTR(ret); - ret = drmm_add_action_or_reset(dev, drmm_crtc_alloc_with_planes_cleanup, - crtc); - if (ret) - return ERR_PTR(ret); - return container; } EXPORT_SYMBOL(__drmm_crtc_alloc_with_planes); diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 8a6d54515f92..457448cc60f7 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -45,7 +45,6 @@ #include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_print.h> #include <drm/drm_vblank.h> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index bbc25e3b7220..90a5e26eafa8 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -5165,6 +5165,51 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode) mode->clock = clock; } +static void drm_calculate_luminance_range(struct drm_connector *connector) +{ + struct hdr_static_metadata *hdr_metadata = &connector->hdr_sink_metadata.hdmi_type1; + struct drm_luminance_range_info *luminance_range = + &connector->display_info.luminance_range; + static const u8 pre_computed_values[] = { + 50, 51, 52, 53, 55, 56, 57, 58, 59, 61, 62, 63, 65, 66, 68, 69, + 71, 72, 74, 75, 77, 79, 81, 82, 84, 86, 88, 90, 92, 94, 96, 98 + }; + u32 max_avg, min_cll, max, min, q, r; + + if (!(hdr_metadata->metadata_type & BIT(HDMI_STATIC_METADATA_TYPE1))) + return; + + max_avg = hdr_metadata->max_fall; + min_cll = hdr_metadata->min_cll; + + /* + * From the specification (CTA-861-G), for calculating the maximum + * luminance we need to use: + * Luminance = 50*2**(CV/32) + * Where CV is a one-byte value. + * For calculating this expression we may need float point precision; + * to avoid this complexity level, we take advantage that CV is divided + * by a constant. From the Euclids division algorithm, we know that CV + * can be written as: CV = 32*q + r. Next, we replace CV in the + * Luminance expression and get 50*(2**q)*(2**(r/32)), hence we just + * need to pre-compute the value of r/32. For pre-computing the values + * We just used the following Ruby line: + * (0...32).each {|cv| puts (50*2**(cv/32.0)).round} + * The results of the above expressions can be verified at + * pre_computed_values. + */ + q = max_avg >> 5; + r = max_avg % 32; + max = (1 << q) * pre_computed_values[r]; + + /* min luminance: maxLum * (CV/255)^2 / 100 */ + q = DIV_ROUND_CLOSEST(min_cll, 255); + min = max * DIV_ROUND_CLOSEST((q * q), 100); + + luminance_range->min_luminance = min; + luminance_range->max_luminance = max; +} + static uint8_t eotf_supported(const u8 *edid_ext) { return edid_ext[2] & @@ -5196,8 +5241,12 @@ drm_parse_hdr_metadata_block(struct drm_connector *connector, const u8 *db) connector->hdr_sink_metadata.hdmi_type1.max_cll = db[4]; if (len >= 5) connector->hdr_sink_metadata.hdmi_type1.max_fall = db[5]; - if (len >= 6) + if (len >= 6) { connector->hdr_sink_metadata.hdmi_type1.min_cll = db[6]; + + /* Calculate only when all values are available */ + drm_calculate_luminance_range(connector); + } } static void @@ -6101,6 +6150,7 @@ static void drm_reset_display_info(struct drm_connector *connector) info->non_desktop = 0; memset(&info->monitor_range, 0, sizeof(info->monitor_range)); + memset(&info->luminance_range, 0, sizeof(info->luminance_range)); info->mso_stream_count = 0; info->mso_pixel_overlap = 0; diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c index a940024c8087..1143bc7f3252 100644 --- a/drivers/gpu/drm/drm_encoder.c +++ b/drivers/gpu/drm/drm_encoder.c @@ -27,6 +27,7 @@ #include <drm/drm_drv.h> #include <drm/drm_encoder.h> #include <drm/drm_managed.h> +#include <drm/drm_print.h> #include "drm_crtc_internal.h" @@ -148,9 +149,9 @@ out_put: * the encoder structure. The encoder structure should not be allocated with * devm_kzalloc(). * - * Note: consider using drmm_encoder_alloc() instead of drm_encoder_init() to - * let the DRM managed resource infrastructure take care of cleanup and - * deallocation. + * Note: consider using drmm_encoder_alloc() or drmm_encoder_init() + * instead of drm_encoder_init() to let the DRM managed resource + * infrastructure take care of cleanup and deallocation. * * Returns: * Zero on success, error code on failure. @@ -212,6 +213,30 @@ static void drmm_encoder_alloc_release(struct drm_device *dev, void *ptr) drm_encoder_cleanup(encoder); } +__printf(5, 0) +static int __drmm_encoder_init(struct drm_device *dev, + struct drm_encoder *encoder, + const struct drm_encoder_funcs *funcs, + int encoder_type, + const char *name, + va_list args) +{ + int ret; + + if (drm_WARN_ON(dev, funcs && funcs->destroy)) + return -EINVAL; + + ret = __drm_encoder_init(dev, encoder, funcs, encoder_type, name, args); + if (ret) + return ret; + + ret = drmm_add_action_or_reset(dev, drmm_encoder_alloc_release, encoder); + if (ret) + return ret; + + return 0; +} + void *__drmm_encoder_alloc(struct drm_device *dev, size_t size, size_t offset, const struct drm_encoder_funcs *funcs, int encoder_type, const char *name, ...) @@ -221,9 +246,6 @@ void *__drmm_encoder_alloc(struct drm_device *dev, size_t size, size_t offset, va_list ap; int ret; - if (WARN_ON(funcs && funcs->destroy)) - return ERR_PTR(-EINVAL); - container = drmm_kzalloc(dev, size, GFP_KERNEL); if (!container) return ERR_PTR(-ENOMEM); @@ -231,19 +253,50 @@ void *__drmm_encoder_alloc(struct drm_device *dev, size_t size, size_t offset, encoder = container + offset; va_start(ap, name); - ret = __drm_encoder_init(dev, encoder, funcs, encoder_type, name, ap); + ret = __drmm_encoder_init(dev, encoder, funcs, encoder_type, name, ap); va_end(ap); if (ret) return ERR_PTR(ret); - ret = drmm_add_action_or_reset(dev, drmm_encoder_alloc_release, encoder); - if (ret) - return ERR_PTR(ret); - return container; } EXPORT_SYMBOL(__drmm_encoder_alloc); +/** + * drmm_encoder_init - Initialize a preallocated encoder + * @dev: drm device + * @encoder: the encoder to init + * @funcs: callbacks for this encoder (optional) + * @encoder_type: user visible type of the encoder + * @name: printf style format string for the encoder name, or NULL for default name + * + * Initializes a preallocated encoder. Encoder should be subclassed as + * part of driver encoder objects. Cleanup is automatically handled + * through registering drm_encoder_cleanup() with drmm_add_action(). The + * encoder structure should be allocated with drmm_kzalloc(). + * + * The @drm_encoder_funcs.destroy hook must be NULL. + * + * Returns: + * Zero on success, error code on failure. + */ +int drmm_encoder_init(struct drm_device *dev, struct drm_encoder *encoder, + const struct drm_encoder_funcs *funcs, + int encoder_type, const char *name, ...) +{ + va_list ap; + int ret; + + va_start(ap, name); + ret = __drmm_encoder_init(dev, encoder, funcs, encoder_type, name, ap); + va_end(ap); + if (ret) + return ret; + + return 0; +} +EXPORT_SYMBOL(drmm_encoder_init); + static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder) { struct drm_connector *connector; diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_dma_helper.c index 69c57273b184..3b535ad1b07c 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_dma_helper.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * drm kms/fb cma (contiguous memory allocator) helper functions + * drm kms/fb dma helper functions * * Copyright (C) 2012 Analog Devices Inc. * Author: Lars-Peter Clausen <lars@metafoo.de> @@ -10,35 +10,40 @@ */ #include <drm/drm_damage_helper.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_plane.h> #include <linux/dma-mapping.h> #include <linux/module.h> /** - * DOC: framebuffer cma helper functions + * DOC: framebuffer dma helper functions * - * Provides helper functions for creating a cma (contiguous memory allocator) - * backed framebuffer. + * Provides helper functions for creating a DMA-contiguous framebuffer. + * + * Depending on the platform, the buffers may be physically non-contiguous and + * mapped through an IOMMU or a similar mechanism, or allocated from + * physically-contiguous memory (using, for instance, CMA or a pool of memory + * reserved at early boot). This is handled behind the scenes by the DMA mapping + * API. * * drm_gem_fb_create() is used in the &drm_mode_config_funcs.fb_create - * callback function to create a cma backed framebuffer. + * callback function to create a DMA-contiguous framebuffer. */ /** - * drm_fb_cma_get_gem_obj() - Get CMA GEM object for framebuffer + * drm_fb_dma_get_gem_obj() - Get DMA GEM object for framebuffer * @fb: The framebuffer * @plane: Which plane * - * Return the CMA GEM object for given framebuffer. + * Return the DMA GEM object for given framebuffer. * * This function will usually be called from the CRTC callback functions. */ -struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb, +struct drm_gem_dma_object *drm_fb_dma_get_gem_obj(struct drm_framebuffer *fb, unsigned int plane) { struct drm_gem_object *gem; @@ -47,27 +52,27 @@ struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb, if (!gem) return NULL; - return to_drm_gem_cma_obj(gem); + return to_drm_gem_dma_obj(gem); } -EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj); +EXPORT_SYMBOL_GPL(drm_fb_dma_get_gem_obj); /** - * drm_fb_cma_get_gem_addr() - Get physical address for framebuffer, for pixel + * drm_fb_dma_get_gem_addr() - Get DMA (bus) address for framebuffer, for pixel * formats where values are grouped in blocks this will get you the beginning of * the block * @fb: The framebuffer * @state: Which state of drm plane * @plane: Which plane - * Return the CMA GEM address for given framebuffer. + * Return the DMA GEM address for given framebuffer. * * This function will usually be called from the PLANE callback functions. */ -dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb, +dma_addr_t drm_fb_dma_get_gem_addr(struct drm_framebuffer *fb, struct drm_plane_state *state, unsigned int plane) { - struct drm_gem_cma_object *obj; - dma_addr_t paddr; + struct drm_gem_dma_object *obj; + dma_addr_t dma_addr; u8 h_div = 1, v_div = 1; u32 block_w = drm_format_info_block_width(fb->format, plane); u32 block_h = drm_format_info_block_height(fb->format, plane); @@ -77,11 +82,11 @@ dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb, u32 block_start_y; u32 num_hblocks; - obj = drm_fb_cma_get_gem_obj(fb, plane); + obj = drm_fb_dma_get_gem_obj(fb, plane); if (!obj) return 0; - paddr = obj->paddr + fb->offsets[plane]; + dma_addr = obj->dma_addr + fb->offsets[plane]; if (plane > 0) { h_div = fb->format->hsub; @@ -93,43 +98,43 @@ dma_addr_t drm_fb_cma_get_gem_addr(struct drm_framebuffer *fb, block_start_y = (sample_y / block_h) * block_h; num_hblocks = sample_x / block_w; - paddr += fb->pitches[plane] * block_start_y; - paddr += block_size * num_hblocks; + dma_addr += fb->pitches[plane] * block_start_y; + dma_addr += block_size * num_hblocks; - return paddr; + return dma_addr; } -EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_addr); +EXPORT_SYMBOL_GPL(drm_fb_dma_get_gem_addr); /** - * drm_fb_cma_sync_non_coherent - Sync GEM object to non-coherent backing + * drm_fb_dma_sync_non_coherent - Sync GEM object to non-coherent backing * memory * @drm: DRM device * @old_state: Old plane state * @state: New plane state * * This function can be used by drivers that use damage clips and have - * CMA GEM objects backed by non-coherent memory. Calling this function + * DMA GEM objects backed by non-coherent memory. Calling this function * in a plane's .atomic_update ensures that all the data in the backing * memory have been written to RAM. */ -void drm_fb_cma_sync_non_coherent(struct drm_device *drm, +void drm_fb_dma_sync_non_coherent(struct drm_device *drm, struct drm_plane_state *old_state, struct drm_plane_state *state) { const struct drm_format_info *finfo = state->fb->format; struct drm_atomic_helper_damage_iter iter; - const struct drm_gem_cma_object *cma_obj; + const struct drm_gem_dma_object *dma_obj; unsigned int offset, i; struct drm_rect clip; dma_addr_t daddr; size_t nb_bytes; for (i = 0; i < finfo->num_planes; i++) { - cma_obj = drm_fb_cma_get_gem_obj(state->fb, i); - if (!cma_obj->map_noncoherent) + dma_obj = drm_fb_dma_get_gem_obj(state->fb, i); + if (!dma_obj->map_noncoherent) continue; - daddr = drm_fb_cma_get_gem_addr(state->fb, state, i); + daddr = drm_fb_dma_get_gem_addr(state->fb, state, i); drm_atomic_helper_damage_iter_init(&iter, old_state, state); drm_atomic_for_each_plane_damage(&iter, &clip) { @@ -142,4 +147,4 @@ void drm_fb_cma_sync_non_coherent(struct drm_device *drm, } } } -EXPORT_SYMBOL_GPL(drm_fb_cma_sync_non_coherent); +EXPORT_SYMBOL_GPL(drm_fb_dma_sync_non_coherent); diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 2d4cee6a10ff..71edb80fe0fb 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -377,12 +377,31 @@ static void drm_fb_helper_damage_blit_real(struct drm_fb_helper *fb_helper, struct iosys_map *dst) { struct drm_framebuffer *fb = fb_helper->fb; - unsigned int cpp = fb->format->cpp[0]; - size_t offset = clip->y1 * fb->pitches[0] + clip->x1 * cpp; - void *src = fb_helper->fbdev->screen_buffer + offset; - size_t len = (clip->x2 - clip->x1) * cpp; + size_t offset = clip->y1 * fb->pitches[0]; + size_t len = clip->x2 - clip->x1; unsigned int y; + void *src; + switch (drm_format_info_bpp(fb->format, 0)) { + case 1: + offset += clip->x1 / 8; + len = DIV_ROUND_UP(len + clip->x1 % 8, 8); + break; + case 2: + offset += clip->x1 / 4; + len = DIV_ROUND_UP(len + clip->x1 % 4, 4); + break; + case 4: + offset += clip->x1 / 2; + len = DIV_ROUND_UP(len + clip->x1 % 2, 2); + break; + default: + offset += clip->x1 * fb->format->cpp[0]; + len *= fb->format->cpp[0]; + break; + } + + src = fb_helper->fbdev->screen_buffer + offset; iosys_map_incr(dst, offset); /* go to first pixel within clip rect */ for (y = clip->y1; y < clip->y2; y++) { @@ -1274,19 +1293,23 @@ static bool drm_fb_pixel_format_equal(const struct fb_var_screeninfo *var_1, } static void drm_fb_helper_fill_pixel_fmt(struct fb_var_screeninfo *var, - u8 depth) + const struct drm_format_info *format) { - switch (depth) { - case 8: + u8 depth = format->depth; + + if (format->is_color_indexed) { var->red.offset = 0; var->green.offset = 0; var->blue.offset = 0; - var->red.length = 8; /* 8bit DAC */ - var->green.length = 8; - var->blue.length = 8; + var->red.length = depth; + var->green.length = depth; + var->blue.length = depth; var->transp.offset = 0; var->transp.length = 0; - break; + return; + } + + switch (depth) { case 15: var->red.offset = 10; var->green.offset = 5; @@ -1341,7 +1364,9 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, { struct drm_fb_helper *fb_helper = info->par; struct drm_framebuffer *fb = fb_helper->fb; + const struct drm_format_info *format = fb->format; struct drm_device *dev = fb_helper->dev; + unsigned int bpp; if (in_dbg_master()) return -EINVAL; @@ -1351,22 +1376,33 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, var->pixclock = 0; } - if ((drm_format_info_block_width(fb->format, 0) > 1) || - (drm_format_info_block_height(fb->format, 0) > 1)) - return -EINVAL; + switch (format->format) { + case DRM_FORMAT_C1: + case DRM_FORMAT_C2: + case DRM_FORMAT_C4: + /* supported format with sub-byte pixels */ + break; + + default: + if ((drm_format_info_block_width(format, 0) > 1) || + (drm_format_info_block_height(format, 0) > 1)) + return -EINVAL; + break; + } /* * Changes struct fb_var_screeninfo are currently not pushed back * to KMS, hence fail if different settings are requested. */ - if (var->bits_per_pixel > fb->format->cpp[0] * 8 || + bpp = drm_format_info_bpp(format, 0); + if (var->bits_per_pixel > bpp || var->xres > fb->width || var->yres > fb->height || var->xres_virtual > fb->width || var->yres_virtual > fb->height) { drm_dbg_kms(dev, "fb requested width/height/bpp can't fit in current fb " "request %dx%d-%d (virtual %dx%d) > %dx%d-%d\n", var->xres, var->yres, var->bits_per_pixel, var->xres_virtual, var->yres_virtual, - fb->width, fb->height, fb->format->cpp[0] * 8); + fb->width, fb->height, bpp); return -EINVAL; } @@ -1381,13 +1417,13 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, !var->blue.length && !var->transp.length && !var->red.msb_right && !var->green.msb_right && !var->blue.msb_right && !var->transp.msb_right) { - drm_fb_helper_fill_pixel_fmt(var, fb->format->depth); + drm_fb_helper_fill_pixel_fmt(var, format); } /* * Likewise, bits_per_pixel should be rounded up to a supported value. */ - var->bits_per_pixel = fb->format->cpp[0] * 8; + var->bits_per_pixel = bpp; /* * drm fbdev emulation doesn't support changing the pixel format at all, @@ -1723,11 +1759,11 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, } static void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, - uint32_t depth) + bool is_color_indexed) { info->fix.type = FB_TYPE_PACKED_PIXELS; - info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR : - FB_VISUAL_TRUECOLOR; + info->fix.visual = is_color_indexed ? FB_VISUAL_PSEUDOCOLOR + : FB_VISUAL_TRUECOLOR; info->fix.mmio_start = 0; info->fix.mmio_len = 0; info->fix.type_aux = 0; @@ -1744,19 +1780,31 @@ static void drm_fb_helper_fill_var(struct fb_info *info, uint32_t fb_width, uint32_t fb_height) { struct drm_framebuffer *fb = fb_helper->fb; + const struct drm_format_info *format = fb->format; + + switch (format->format) { + case DRM_FORMAT_C1: + case DRM_FORMAT_C2: + case DRM_FORMAT_C4: + /* supported format with sub-byte pixels */ + break; + + default: + WARN_ON((drm_format_info_block_width(format, 0) > 1) || + (drm_format_info_block_height(format, 0) > 1)); + break; + } - WARN_ON((drm_format_info_block_width(fb->format, 0) > 1) || - (drm_format_info_block_height(fb->format, 0) > 1)); info->pseudo_palette = fb_helper->pseudo_palette; info->var.xres_virtual = fb->width; info->var.yres_virtual = fb->height; - info->var.bits_per_pixel = fb->format->cpp[0] * 8; + info->var.bits_per_pixel = drm_format_info_bpp(format, 0); info->var.accel_flags = FB_ACCELF_TEXT; info->var.xoffset = 0; info->var.yoffset = 0; info->var.activate = FB_ACTIVATE_NOW; - drm_fb_helper_fill_pixel_fmt(&info->var, fb->format->depth); + drm_fb_helper_fill_pixel_fmt(&info->var, format); info->var.xres = fb_width; info->var.yres = fb_height; @@ -1781,7 +1829,8 @@ void drm_fb_helper_fill_info(struct fb_info *info, { struct drm_framebuffer *fb = fb_helper->fb; - drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth); + drm_fb_helper_fill_fix(info, fb->pitches[0], + fb->format->is_color_indexed); drm_fb_helper_fill_var(info, fb_helper, sizes->fb_width, sizes->fb_height); diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index dc7d2e5b16c8..a8b4d918e9a3 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -48,11 +48,6 @@ #include "drm_internal.h" #include "drm_legacy.h" -#if defined(CONFIG_MMU) && defined(CONFIG_TRANSPARENT_HUGEPAGE) -#include <uapi/asm/mman.h> -#include <drm/drm_vma_manager.h> -#endif - /* from BKL pushdown */ DEFINE_MUTEX(drm_global_mutex); @@ -131,7 +126,7 @@ bool drm_dev_needs_global_mutex(struct drm_device *dev) * }; * * For plain GEM based drivers there is the DEFINE_DRM_GEM_FOPS() macro, and for - * CMA based drivers there is the DEFINE_DRM_GEM_CMA_FOPS() macro to make this + * DMA based drivers there is the DEFINE_DRM_GEM_DMA_FOPS() macro to make this * simpler. * * The driver's &file_operations must be stored in &drm_driver.fops. @@ -912,139 +907,3 @@ struct file *mock_drm_getfile(struct drm_minor *minor, unsigned int flags) return file; } EXPORT_SYMBOL_FOR_TESTS_ONLY(mock_drm_getfile); - -#ifdef CONFIG_MMU -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -/* - * drm_addr_inflate() attempts to construct an aligned area by inflating - * the area size and skipping the unaligned start of the area. - * adapted from shmem_get_unmapped_area() - */ -static unsigned long drm_addr_inflate(unsigned long addr, - unsigned long len, - unsigned long pgoff, - unsigned long flags, - unsigned long huge_size) -{ - unsigned long offset, inflated_len; - unsigned long inflated_addr; - unsigned long inflated_offset; - - offset = (pgoff << PAGE_SHIFT) & (huge_size - 1); - if (offset && offset + len < 2 * huge_size) - return addr; - if ((addr & (huge_size - 1)) == offset) - return addr; - - inflated_len = len + huge_size - PAGE_SIZE; - if (inflated_len > TASK_SIZE) - return addr; - if (inflated_len < len) - return addr; - - inflated_addr = current->mm->get_unmapped_area(NULL, 0, inflated_len, - 0, flags); - if (IS_ERR_VALUE(inflated_addr)) - return addr; - if (inflated_addr & ~PAGE_MASK) - return addr; - - inflated_offset = inflated_addr & (huge_size - 1); - inflated_addr += offset - inflated_offset; - if (inflated_offset > offset) - inflated_addr += huge_size; - - if (inflated_addr > TASK_SIZE - len) - return addr; - - return inflated_addr; -} - -/** - * drm_get_unmapped_area() - Get an unused user-space virtual memory area - * suitable for huge page table entries. - * @file: The struct file representing the address space being mmap()'d. - * @uaddr: Start address suggested by user-space. - * @len: Length of the area. - * @pgoff: The page offset into the address space. - * @flags: mmap flags - * @mgr: The address space manager used by the drm driver. This argument can - * probably be removed at some point when all drivers use the same - * address space manager. - * - * This function attempts to find an unused user-space virtual memory area - * that can accommodate the size we want to map, and that is properly - * aligned to facilitate huge page table entries matching actual - * huge pages or huge page aligned memory in buffer objects. Buffer objects - * are assumed to start at huge page boundary pfns (io memory) or be - * populated by huge pages aligned to the start of the buffer object - * (system- or coherent memory). Adapted from shmem_get_unmapped_area. - * - * Return: aligned user-space address. - */ -unsigned long drm_get_unmapped_area(struct file *file, - unsigned long uaddr, unsigned long len, - unsigned long pgoff, unsigned long flags, - struct drm_vma_offset_manager *mgr) -{ - unsigned long addr; - unsigned long inflated_addr; - struct drm_vma_offset_node *node; - - if (len > TASK_SIZE) - return -ENOMEM; - - /* - * @pgoff is the file page-offset the huge page boundaries of - * which typically aligns to physical address huge page boundaries. - * That's not true for DRM, however, where physical address huge - * page boundaries instead are aligned with the offset from - * buffer object start. So adjust @pgoff to be the offset from - * buffer object start. - */ - drm_vma_offset_lock_lookup(mgr); - node = drm_vma_offset_lookup_locked(mgr, pgoff, 1); - if (node) - pgoff -= node->vm_node.start; - drm_vma_offset_unlock_lookup(mgr); - - addr = current->mm->get_unmapped_area(file, uaddr, len, pgoff, flags); - if (IS_ERR_VALUE(addr)) - return addr; - if (addr & ~PAGE_MASK) - return addr; - if (addr > TASK_SIZE - len) - return addr; - - if (len < HPAGE_PMD_SIZE) - return addr; - if (flags & MAP_FIXED) - return addr; - /* - * Our priority is to support MAP_SHARED mapped hugely; - * and support MAP_PRIVATE mapped hugely too, until it is COWed. - * But if caller specified an address hint, respect that as before. - */ - if (uaddr) - return addr; - - inflated_addr = drm_addr_inflate(addr, len, pgoff, flags, - HPAGE_PMD_SIZE); - - if (IS_ENABLED(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD) && - len >= HPAGE_PUD_SIZE) - inflated_addr = drm_addr_inflate(inflated_addr, len, pgoff, - flags, HPAGE_PUD_SIZE); - return inflated_addr; -} -#else /* CONFIG_TRANSPARENT_HUGEPAGE */ -unsigned long drm_get_unmapped_area(struct file *file, - unsigned long uaddr, unsigned long len, - unsigned long pgoff, unsigned long flags, - struct drm_vma_offset_manager *mgr) -{ - return current->mm->get_unmapped_area(file, uaddr, len, pgoff, flags); -} -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ -EXPORT_SYMBOL_GPL(drm_get_unmapped_area); -#endif /* CONFIG_MMU */ diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c index a3ccd8bc966f..56642816fdff 100644 --- a/drivers/gpu/drm/drm_format_helper.c +++ b/drivers/gpu/drm/drm_format_helper.c @@ -8,9 +8,10 @@ * (at your option) any later version. */ +#include <linux/io.h> +#include <linux/iosys-map.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/io.h> #include <drm/drm_device.h> #include <drm/drm_format_helper.h> @@ -40,11 +41,11 @@ unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info } EXPORT_SYMBOL(drm_fb_clip_offset); -/* TODO: Make this functon work with multi-plane formats. */ -static int drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_pixsize, - const void *vaddr, const struct drm_framebuffer *fb, - const struct drm_rect *clip, bool vaddr_cached_hint, - void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels)) +/* TODO: Make this function work with multi-plane formats. */ +static int __drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_pixsize, + const void *vaddr, const struct drm_framebuffer *fb, + const struct drm_rect *clip, bool vaddr_cached_hint, + void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels)) { unsigned long linepixels = drm_rect_width(clip); unsigned long lines = drm_rect_height(clip); @@ -54,7 +55,7 @@ static int drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_pix const void *sbuf; /* - * Some source buffers, such as CMA memory, use write-combine + * Some source buffers, such as DMA memory, use write-combine * caching, so reads are uncached. Speed up access by fetching * one line at a time. */ @@ -83,11 +84,11 @@ static int drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_pix return 0; } -/* TODO: Make this functon work with multi-plane formats. */ -static int drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsigned long dst_pixsize, - const void *vaddr, const struct drm_framebuffer *fb, - const struct drm_rect *clip, bool vaddr_cached_hint, - void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels)) +/* TODO: Make this function work with multi-plane formats. */ +static int __drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsigned long dst_pixsize, + const void *vaddr, const struct drm_framebuffer *fb, + const struct drm_rect *clip, bool vaddr_cached_hint, + void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels)) { unsigned long linepixels = drm_rect_width(clip); unsigned long lines = drm_rect_height(clip); @@ -128,65 +129,82 @@ static int drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsigned return 0; } -/** - * drm_fb_memcpy - Copy clip buffer - * @dst: Destination buffer - * @dst_pitch: Number of bytes between two consecutive scanlines within dst - * @vaddr: Source buffer - * @fb: DRM framebuffer - * @clip: Clip rectangle area to copy - * - * This function does not apply clipping on dst, i.e. the destination - * is at the top-left corner. - */ -void drm_fb_memcpy(void *dst, unsigned int dst_pitch, const void *vaddr, - const struct drm_framebuffer *fb, const struct drm_rect *clip) +/* TODO: Make this function work with multi-plane formats. */ +static int drm_fb_xfrm(struct iosys_map *dst, + const unsigned int *dst_pitch, const u8 *dst_pixsize, + const struct iosys_map *src, const struct drm_framebuffer *fb, + const struct drm_rect *clip, bool vaddr_cached_hint, + void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels)) { - unsigned int cpp = fb->format->cpp[0]; - size_t len = (clip->x2 - clip->x1) * cpp; - unsigned int y, lines = clip->y2 - clip->y1; + static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = { + 0, 0, 0, 0 + }; if (!dst_pitch) - dst_pitch = len; + dst_pitch = default_dst_pitch; - vaddr += clip_offset(clip, fb->pitches[0], cpp); - for (y = 0; y < lines; y++) { - memcpy(dst, vaddr, len); - vaddr += fb->pitches[0]; - dst += dst_pitch; - } + /* TODO: handle src in I/O memory here */ + if (dst[0].is_iomem) + return __drm_fb_xfrm_toio(dst[0].vaddr_iomem, dst_pitch[0], dst_pixsize[0], + src[0].vaddr, fb, clip, vaddr_cached_hint, xfrm_line); + else + return __drm_fb_xfrm(dst[0].vaddr, dst_pitch[0], dst_pixsize[0], + src[0].vaddr, fb, clip, vaddr_cached_hint, xfrm_line); } -EXPORT_SYMBOL(drm_fb_memcpy); /** - * drm_fb_memcpy_toio - Copy clip buffer - * @dst: Destination buffer (iomem) - * @dst_pitch: Number of bytes between two consecutive scanlines within dst - * @vaddr: Source buffer + * drm_fb_memcpy - Copy clip buffer + * @dst: Array of destination buffers + * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines + * within @dst; can be NULL if scanlines are stored next to each other. + * @src: Array of source buffers * @fb: DRM framebuffer * @clip: Clip rectangle area to copy * - * This function does not apply clipping on dst, i.e. the destination - * is at the top-left corner. + * This function copies parts of a framebuffer to display memory. Destination and + * framebuffer formats must match. No conversion takes place. The parameters @dst, + * @dst_pitch and @src refer to arrays. Each array must have at least as many entries + * as there are planes in @fb's format. Each entry stores the value for the format's + * respective color plane at the same index. + * + * This function does not apply clipping on @dst (i.e. the destination is at the + * top-left corner). */ -void drm_fb_memcpy_toio(void __iomem *dst, unsigned int dst_pitch, const void *vaddr, - const struct drm_framebuffer *fb, const struct drm_rect *clip) +void drm_fb_memcpy(struct iosys_map *dst, const unsigned int *dst_pitch, + const struct iosys_map *src, const struct drm_framebuffer *fb, + const struct drm_rect *clip) { - unsigned int cpp = fb->format->cpp[0]; - size_t len = (clip->x2 - clip->x1) * cpp; - unsigned int y, lines = clip->y2 - clip->y1; + static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = { + 0, 0, 0, 0 + }; - if (!dst_pitch) - dst_pitch = len; + const struct drm_format_info *format = fb->format; + unsigned int i, y, lines = drm_rect_height(clip); - vaddr += clip_offset(clip, fb->pitches[0], cpp); - for (y = 0; y < lines; y++) { - memcpy_toio(dst, vaddr, len); - vaddr += fb->pitches[0]; - dst += dst_pitch; + if (!dst_pitch) + dst_pitch = default_dst_pitch; + + for (i = 0; i < format->num_planes; ++i) { + unsigned int bpp_i = drm_format_info_bpp(format, i); + unsigned int cpp_i = DIV_ROUND_UP(bpp_i, 8); + size_t len_i = DIV_ROUND_UP(drm_rect_width(clip) * bpp_i, 8); + unsigned int dst_pitch_i = dst_pitch[i]; + struct iosys_map dst_i = dst[i]; + struct iosys_map src_i = src[i]; + + if (!dst_pitch_i) + dst_pitch_i = len_i; + + iosys_map_incr(&src_i, clip_offset(clip, fb->pitches[i], cpp_i)); + for (y = 0; y < lines; y++) { + /* TODO: handle src_i in I/O memory here */ + iosys_map_memcpy_to(&dst_i, 0, src_i.vaddr, len_i); + iosys_map_incr(&src_i, fb->pitches[i]); + iosys_map_incr(&dst_i, dst_pitch_i); + } } } -EXPORT_SYMBOL(drm_fb_memcpy_toio); +EXPORT_SYMBOL(drm_fb_memcpy); static void drm_fb_swab16_line(void *dbuf, const void *sbuf, unsigned int pixels) { @@ -210,37 +228,47 @@ static void drm_fb_swab32_line(void *dbuf, const void *sbuf, unsigned int pixels /** * drm_fb_swab - Swap bytes into clip buffer - * @dst: Destination buffer - * @dst_pitch: Number of bytes between two consecutive scanlines within dst - * @src: Source buffer + * @dst: Array of destination buffers + * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines + * within @dst; can be NULL if scanlines are stored next to each other. + * @src: Array of source buffers * @fb: DRM framebuffer * @clip: Clip rectangle area to copy * @cached: Source buffer is mapped cached (eg. not write-combined) * - * If @cached is false a temporary buffer is used to cache one pixel line at a - * time to speed up slow uncached reads. + * This function copies parts of a framebuffer to display memory and swaps per-pixel + * bytes during the process. Destination and framebuffer formats must match. The + * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at + * least as many entries as there are planes in @fb's format. Each entry stores the + * value for the format's respective color plane at the same index. If @cached is + * false a temporary buffer is used to cache one pixel line at a time to speed up + * slow uncached reads. * - * This function does not apply clipping on dst, i.e. the destination - * is at the top-left corner. + * This function does not apply clipping on @dst (i.e. the destination is at the + * top-left corner). */ -void drm_fb_swab(void *dst, unsigned int dst_pitch, const void *src, - const struct drm_framebuffer *fb, const struct drm_rect *clip, - bool cached) +void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch, + const struct iosys_map *src, const struct drm_framebuffer *fb, + const struct drm_rect *clip, bool cached) { - u8 cpp = fb->format->cpp[0]; + const struct drm_format_info *format = fb->format; + u8 cpp = DIV_ROUND_UP(drm_format_info_bpp(format, 0), 8); + void (*swab_line)(void *dbuf, const void *sbuf, unsigned int npixels); switch (cpp) { case 4: - drm_fb_xfrm(dst, dst_pitch, cpp, src, fb, clip, cached, drm_fb_swab32_line); + swab_line = drm_fb_swab32_line; break; case 2: - drm_fb_xfrm(dst, dst_pitch, cpp, src, fb, clip, cached, drm_fb_swab16_line); + swab_line = drm_fb_swab16_line; break; default: drm_warn_once(fb->dev, "Format %p4cc has unsupported pixel size.\n", - &fb->format->format); - break; + &format->format); + return; } + + drm_fb_xfrm(dst, dst_pitch, &cpp, src, fb, clip, cached, swab_line); } EXPORT_SYMBOL(drm_fb_swab); @@ -261,32 +289,50 @@ static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigne /** * drm_fb_xrgb8888_to_rgb332 - Convert XRGB8888 to RGB332 clip buffer - * @dst: RGB332 destination buffer - * @dst_pitch: Number of bytes between two consecutive scanlines within dst - * @src: XRGB8888 source buffer + * @dst: Array of RGB332 destination buffers + * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines + * within @dst; can be NULL if scanlines are stored next to each other. + * @src: Array of XRGB8888 source buffers * @fb: DRM framebuffer * @clip: Clip rectangle area to copy * - * Drivers can use this function for RGB332 devices that don't natively support XRGB8888. + * This function copies parts of a framebuffer to display memory and converts the + * color format during the process. Destination and framebuffer formats must match. The + * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at + * least as many entries as there are planes in @fb's format. Each entry stores the + * value for the format's respective color plane at the same index. + * + * This function does not apply clipping on @dst (i.e. the destination is at the + * top-left corner). + * + * Drivers can use this function for RGB332 devices that don't support XRGB8888 natively. */ -void drm_fb_xrgb8888_to_rgb332(void *dst, unsigned int dst_pitch, const void *src, - const struct drm_framebuffer *fb, const struct drm_rect *clip) +void drm_fb_xrgb8888_to_rgb332(struct iosys_map *dst, const unsigned int *dst_pitch, + const struct iosys_map *src, const struct drm_framebuffer *fb, + const struct drm_rect *clip) { - drm_fb_xfrm(dst, dst_pitch, 1, src, fb, clip, false, drm_fb_xrgb8888_to_rgb332_line); + static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { + 1, + }; + + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xrgb8888_to_rgb332_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb332); static void drm_fb_xrgb8888_to_rgb565_line(void *dbuf, const void *sbuf, unsigned int pixels) { u16 *dbuf16 = dbuf; - const u32 *sbuf32 = sbuf; + const __le32 *sbuf32 = sbuf; unsigned int x; u16 val16; + u32 pix; for (x = 0; x < pixels; x++) { - val16 = ((sbuf32[x] & 0x00F80000) >> 8) | - ((sbuf32[x] & 0x0000FC00) >> 5) | - ((sbuf32[x] & 0x000000F8) >> 3); + pix = le32_to_cpu(sbuf32[x]); + val16 = ((pix & 0x00F80000) >> 8) | + ((pix & 0x0000FC00) >> 5) | + ((pix & 0x000000F8) >> 3); dbuf16[x] = val16; } } @@ -295,146 +341,143 @@ static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf, unsigned int pixels) { u16 *dbuf16 = dbuf; - const u32 *sbuf32 = sbuf; + const __le32 *sbuf32 = sbuf; unsigned int x; u16 val16; + u32 pix; for (x = 0; x < pixels; x++) { - val16 = ((sbuf32[x] & 0x00F80000) >> 8) | - ((sbuf32[x] & 0x0000FC00) >> 5) | - ((sbuf32[x] & 0x000000F8) >> 3); + pix = le32_to_cpu(sbuf32[x]); + val16 = ((pix & 0x00F80000) >> 8) | + ((pix & 0x0000FC00) >> 5) | + ((pix & 0x000000F8) >> 3); dbuf16[x] = swab16(val16); } } /** * drm_fb_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer - * @dst: RGB565 destination buffer - * @dst_pitch: Number of bytes between two consecutive scanlines within dst - * @vaddr: XRGB8888 source buffer + * @dst: Array of RGB565 destination buffers + * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines + * within @dst; can be NULL if scanlines are stored next to each other. + * @src: Array of XRGB8888 source buffer * @fb: DRM framebuffer * @clip: Clip rectangle area to copy * @swab: Swap bytes * - * Drivers can use this function for RGB565 devices that don't natively - * support XRGB8888. - */ -void drm_fb_xrgb8888_to_rgb565(void *dst, unsigned int dst_pitch, const void *vaddr, - const struct drm_framebuffer *fb, const struct drm_rect *clip, - bool swab) -{ - if (swab) - drm_fb_xfrm(dst, dst_pitch, 2, vaddr, fb, clip, false, - drm_fb_xrgb8888_to_rgb565_swab_line); - else - drm_fb_xfrm(dst, dst_pitch, 2, vaddr, fb, clip, false, - drm_fb_xrgb8888_to_rgb565_line); -} -EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565); - -/** - * drm_fb_xrgb8888_to_rgb565_toio - Convert XRGB8888 to RGB565 clip buffer - * @dst: RGB565 destination buffer (iomem) - * @dst_pitch: Number of bytes between two consecutive scanlines within dst - * @vaddr: XRGB8888 source buffer - * @fb: DRM framebuffer - * @clip: Clip rectangle area to copy - * @swab: Swap bytes + * This function copies parts of a framebuffer to display memory and converts the + * color format during the process. Destination and framebuffer formats must match. The + * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at + * least as many entries as there are planes in @fb's format. Each entry stores the + * value for the format's respective color plane at the same index. * - * Drivers can use this function for RGB565 devices that don't natively - * support XRGB8888. + * This function does not apply clipping on @dst (i.e. the destination is at the + * top-left corner). + * + * Drivers can use this function for RGB565 devices that don't support XRGB8888 natively. */ -void drm_fb_xrgb8888_to_rgb565_toio(void __iomem *dst, unsigned int dst_pitch, - const void *vaddr, const struct drm_framebuffer *fb, - const struct drm_rect *clip, bool swab) +void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pitch, + const struct iosys_map *src, const struct drm_framebuffer *fb, + const struct drm_rect *clip, bool swab) { + static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { + 2, + }; + + void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels); + if (swab) - drm_fb_xfrm_toio(dst, dst_pitch, 2, vaddr, fb, clip, false, - drm_fb_xrgb8888_to_rgb565_swab_line); + xfrm_line = drm_fb_xrgb8888_to_rgb565_swab_line; else - drm_fb_xfrm_toio(dst, dst_pitch, 2, vaddr, fb, clip, false, - drm_fb_xrgb8888_to_rgb565_line); + xfrm_line = drm_fb_xrgb8888_to_rgb565_line; + + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, xfrm_line); } -EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565_toio); +EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565); static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigned int pixels) { u8 *dbuf8 = dbuf; - const u32 *sbuf32 = sbuf; + const __le32 *sbuf32 = sbuf; unsigned int x; + u32 pix; for (x = 0; x < pixels; x++) { - *dbuf8++ = (sbuf32[x] & 0x000000FF) >> 0; - *dbuf8++ = (sbuf32[x] & 0x0000FF00) >> 8; - *dbuf8++ = (sbuf32[x] & 0x00FF0000) >> 16; + pix = le32_to_cpu(sbuf32[x]); + *dbuf8++ = (pix & 0x000000FF) >> 0; + *dbuf8++ = (pix & 0x0000FF00) >> 8; + *dbuf8++ = (pix & 0x00FF0000) >> 16; } } /** * drm_fb_xrgb8888_to_rgb888 - Convert XRGB8888 to RGB888 clip buffer - * @dst: RGB888 destination buffer - * @dst_pitch: Number of bytes between two consecutive scanlines within dst - * @src: XRGB8888 source buffer + * @dst: Array of RGB888 destination buffers + * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines + * within @dst; can be NULL if scanlines are stored next to each other. + * @src: Array of XRGB8888 source buffers * @fb: DRM framebuffer * @clip: Clip rectangle area to copy * - * Drivers can use this function for RGB888 devices that don't natively - * support XRGB8888. - */ -void drm_fb_xrgb8888_to_rgb888(void *dst, unsigned int dst_pitch, const void *src, - const struct drm_framebuffer *fb, const struct drm_rect *clip) -{ - drm_fb_xfrm(dst, dst_pitch, 3, src, fb, clip, false, drm_fb_xrgb8888_to_rgb888_line); -} -EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888); - -/** - * drm_fb_xrgb8888_to_rgb888_toio - Convert XRGB8888 to RGB888 clip buffer - * @dst: RGB565 destination buffer (iomem) - * @dst_pitch: Number of bytes between two consecutive scanlines within dst - * @vaddr: XRGB8888 source buffer - * @fb: DRM framebuffer - * @clip: Clip rectangle area to copy + * This function copies parts of a framebuffer to display memory and converts the + * color format during the process. Destination and framebuffer formats must match. The + * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at + * least as many entries as there are planes in @fb's format. Each entry stores the + * value for the format's respective color plane at the same index. + * + * This function does not apply clipping on @dst (i.e. the destination is at the + * top-left corner). * * Drivers can use this function for RGB888 devices that don't natively * support XRGB8888. */ -void drm_fb_xrgb8888_to_rgb888_toio(void __iomem *dst, unsigned int dst_pitch, - const void *vaddr, const struct drm_framebuffer *fb, - const struct drm_rect *clip) +void drm_fb_xrgb8888_to_rgb888(struct iosys_map *dst, const unsigned int *dst_pitch, + const struct iosys_map *src, const struct drm_framebuffer *fb, + const struct drm_rect *clip) { - drm_fb_xfrm_toio(dst, dst_pitch, 3, vaddr, fb, clip, false, - drm_fb_xrgb8888_to_rgb888_line); + static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { + 3, + }; + + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xrgb8888_to_rgb888_line); } -EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888_toio); +EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888); static void drm_fb_rgb565_to_xrgb8888_line(void *dbuf, const void *sbuf, unsigned int pixels) { - u32 *dbuf32 = dbuf; - const u16 *sbuf16 = sbuf; + __le32 *dbuf32 = dbuf; + const __le16 *sbuf16 = sbuf; unsigned int x; - for (x = 0; x < pixels; x++, ++sbuf16, ++dbuf32) { - u32 val32 = ((*sbuf16 & 0xf800) << 8) | - ((*sbuf16 & 0x07e0) << 5) | - ((*sbuf16 & 0x001f) << 3); - *dbuf32 = 0xff000000 | val32 | - ((val32 >> 3) & 0x00070007) | - ((val32 >> 2) & 0x00000300); + for (x = 0; x < pixels; x++) { + u16 val16 = le16_to_cpu(sbuf16[x]); + u32 val32 = ((val16 & 0xf800) << 8) | + ((val16 & 0x07e0) << 5) | + ((val16 & 0x001f) << 3); + val32 = 0xff000000 | val32 | + ((val32 >> 3) & 0x00070007) | + ((val32 >> 2) & 0x00000300); + dbuf32[x] = cpu_to_le32(val32); } } -static void drm_fb_rgb565_to_xrgb8888_toio(void __iomem *dst, unsigned int dst_pitch, - const void *vaddr, const struct drm_framebuffer *fb, - const struct drm_rect *clip) +static void drm_fb_rgb565_to_xrgb8888(struct iosys_map *dst, const unsigned int *dst_pitch, + const struct iosys_map *src, + const struct drm_framebuffer *fb, + const struct drm_rect *clip) { - drm_fb_xfrm_toio(dst, dst_pitch, 4, vaddr, fb, clip, false, - drm_fb_rgb565_to_xrgb8888_line); + static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { + 4, + }; + + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_rgb565_to_xrgb8888_line); } static void drm_fb_rgb888_to_xrgb8888_line(void *dbuf, const void *sbuf, unsigned int pixels) { - u32 *dbuf32 = dbuf; + __le32 *dbuf32 = dbuf; const u8 *sbuf8 = sbuf; unsigned int x; @@ -442,117 +485,158 @@ static void drm_fb_rgb888_to_xrgb8888_line(void *dbuf, const void *sbuf, unsigne u8 r = *sbuf8++; u8 g = *sbuf8++; u8 b = *sbuf8++; - *dbuf32++ = 0xff000000 | (r << 16) | (g << 8) | b; + u32 pix = 0xff000000 | (r << 16) | (g << 8) | b; + dbuf32[x] = cpu_to_le32(pix); } } -static void drm_fb_rgb888_to_xrgb8888_toio(void __iomem *dst, unsigned int dst_pitch, - const void *vaddr, const struct drm_framebuffer *fb, - const struct drm_rect *clip) +static void drm_fb_rgb888_to_xrgb8888(struct iosys_map *dst, const unsigned int *dst_pitch, + const struct iosys_map *src, + const struct drm_framebuffer *fb, + const struct drm_rect *clip) { - drm_fb_xfrm_toio(dst, dst_pitch, 4, vaddr, fb, clip, false, - drm_fb_rgb888_to_xrgb8888_line); + static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { + 4, + }; + + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_rgb888_to_xrgb8888_line); } static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, unsigned int pixels) { - u32 *dbuf32 = dbuf; - const u32 *sbuf32 = sbuf; + __le32 *dbuf32 = dbuf; + const __le32 *sbuf32 = sbuf; unsigned int x; u32 val32; + u32 pix; for (x = 0; x < pixels; x++) { - val32 = ((sbuf32[x] & 0x000000FF) << 2) | - ((sbuf32[x] & 0x0000FF00) << 4) | - ((sbuf32[x] & 0x00FF0000) << 6); - *dbuf32++ = val32 | ((val32 >> 8) & 0x00300C03); + pix = le32_to_cpu(sbuf32[x]); + val32 = ((pix & 0x000000FF) << 2) | + ((pix & 0x0000FF00) << 4) | + ((pix & 0x00FF0000) << 6); + pix = val32 | ((val32 >> 8) & 0x00300C03); + *dbuf32++ = cpu_to_le32(pix); } } /** - * drm_fb_xrgb8888_to_xrgb2101010_toio - Convert XRGB8888 to XRGB2101010 clip - * buffer - * @dst: XRGB2101010 destination buffer (iomem) - * @dst_pitch: Number of bytes between two consecutive scanlines within dst - * @vaddr: XRGB8888 source buffer + * drm_fb_xrgb8888_to_xrgb2101010 - Convert XRGB8888 to XRGB2101010 clip buffer + * @dst: Array of XRGB2101010 destination buffers + * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines + * within @dst; can be NULL if scanlines are stored next to each other. + * @src: Array of XRGB8888 source buffers * @fb: DRM framebuffer * @clip: Clip rectangle area to copy * - * Drivers can use this function for XRGB2101010 devices that don't natively - * support XRGB8888. + * This function copies parts of a framebuffer to display memory and converts the + * color format during the process. Destination and framebuffer formats must match. The + * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at + * least as many entries as there are planes in @fb's format. Each entry stores the + * value for the format's respective color plane at the same index. + * + * This function does not apply clipping on @dst (i.e. the destination is at the + * top-left corner). + * + * Drivers can use this function for XRGB2101010 devices that don't support XRGB8888 + * natively. */ -void drm_fb_xrgb8888_to_xrgb2101010_toio(void __iomem *dst, - unsigned int dst_pitch, const void *vaddr, - const struct drm_framebuffer *fb, - const struct drm_rect *clip) +void drm_fb_xrgb8888_to_xrgb2101010(struct iosys_map *dst, const unsigned int *dst_pitch, + const struct iosys_map *src, const struct drm_framebuffer *fb, + const struct drm_rect *clip) { - drm_fb_xfrm_toio(dst, dst_pitch, 4, vaddr, fb, clip, false, - drm_fb_xrgb8888_to_xrgb2101010_line); + static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { + 4, + }; + + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xrgb8888_to_xrgb2101010_line); } -EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010_toio); static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned int pixels) { u8 *dbuf8 = dbuf; - const u32 *sbuf32 = sbuf; + const __le32 *sbuf32 = sbuf; unsigned int x; for (x = 0; x < pixels; x++) { - u8 r = (*sbuf32 & 0x00ff0000) >> 16; - u8 g = (*sbuf32 & 0x0000ff00) >> 8; - u8 b = *sbuf32 & 0x000000ff; + u32 pix = le32_to_cpu(sbuf32[x]); + u8 r = (pix & 0x00ff0000) >> 16; + u8 g = (pix & 0x0000ff00) >> 8; + u8 b = pix & 0x000000ff; /* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */ *dbuf8++ = (3 * r + 6 * g + b) / 10; - sbuf32++; } } /** * drm_fb_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale - * @dst: 8-bit grayscale destination buffer - * @dst_pitch: Number of bytes between two consecutive scanlines within dst - * @vaddr: XRGB8888 source buffer + * @dst: Array of 8-bit grayscale destination buffers + * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines + * within @dst; can be NULL if scanlines are stored next to each other. + * @src: Array of XRGB8888 source buffers * @fb: DRM framebuffer * @clip: Clip rectangle area to copy * - * Drm doesn't have native monochrome or grayscale support. - * Such drivers can announce the commonly supported XR24 format to userspace - * and use this function to convert to the native format. + * This function copies parts of a framebuffer to display memory and converts the + * color format during the process. Destination and framebuffer formats must match. The + * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at + * least as many entries as there are planes in @fb's format. Each entry stores the + * value for the format's respective color plane at the same index. * - * Monochrome drivers will use the most significant bit, - * where 1 means foreground color and 0 background color. + * This function does not apply clipping on @dst (i.e. the destination is at the + * top-left corner). * - * ITU BT.601 is used for the RGB -> luma (brightness) conversion. + * DRM doesn't have native monochrome or grayscale support. Drivers can use this + * function for grayscale devices that don't support XRGB8888 natively.Such + * drivers can announce the commonly supported XR24 format to userspace and use + * this function to convert to the native format. Monochrome drivers will use the + * most significant bit, where 1 means foreground color and 0 background color. + * ITU BT.601 is being used for the RGB -> luma (brightness) conversion. */ -void drm_fb_xrgb8888_to_gray8(void *dst, unsigned int dst_pitch, const void *vaddr, - const struct drm_framebuffer *fb, const struct drm_rect *clip) +void drm_fb_xrgb8888_to_gray8(struct iosys_map *dst, const unsigned int *dst_pitch, + const struct iosys_map *src, const struct drm_framebuffer *fb, + const struct drm_rect *clip) { - drm_fb_xfrm(dst, dst_pitch, 1, vaddr, fb, clip, false, drm_fb_xrgb8888_to_gray8_line); + static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { + 1, + }; + + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xrgb8888_to_gray8_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8); /** - * drm_fb_blit_toio - Copy parts of a framebuffer to display memory - * @dst: The display memory to copy to - * @dst_pitch: Number of bytes between two consecutive scanlines within dst + * drm_fb_blit - Copy parts of a framebuffer to display memory + * @dst: Array of display-memory addresses to copy to + * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines + * within @dst; can be NULL if scanlines are stored next to each other. * @dst_format: FOURCC code of the display's color format - * @vmap: The framebuffer memory to copy from + * @src: The framebuffer memory to copy from * @fb: The framebuffer to copy from * @clip: Clip rectangle area to copy * * This function copies parts of a framebuffer to display memory. If the * formats of the display and the framebuffer mismatch, the blit function - * will attempt to convert between them. + * will attempt to convert between them during the process. The parameters @dst, + * @dst_pitch and @src refer to arrays. Each array must have at least as many + * entries as there are planes in @dst_format's format. Each entry stores the + * value for the format's respective color plane at the same index. + * + * This function does not apply clipping on @dst (i.e. the destination is at the + * top-left corner). * * Returns: * 0 on success, or * -EINVAL if the color-format conversion failed, or * a negative error code otherwise. */ -int drm_fb_blit_toio(void __iomem *dst, unsigned int dst_pitch, uint32_t dst_format, - const void *vmap, const struct drm_framebuffer *fb, - const struct drm_rect *clip) +int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t dst_format, + const struct iosys_map *src, const struct drm_framebuffer *fb, + const struct drm_rect *clip) { uint32_t fb_format = fb->format->format; @@ -567,30 +651,30 @@ int drm_fb_blit_toio(void __iomem *dst, unsigned int dst_pitch, uint32_t dst_for dst_format = DRM_FORMAT_XRGB2101010; if (dst_format == fb_format) { - drm_fb_memcpy_toio(dst, dst_pitch, vmap, fb, clip); + drm_fb_memcpy(dst, dst_pitch, src, fb, clip); return 0; } else if (dst_format == DRM_FORMAT_RGB565) { if (fb_format == DRM_FORMAT_XRGB8888) { - drm_fb_xrgb8888_to_rgb565_toio(dst, dst_pitch, vmap, fb, clip, false); + drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, false); return 0; } } else if (dst_format == DRM_FORMAT_RGB888) { if (fb_format == DRM_FORMAT_XRGB8888) { - drm_fb_xrgb8888_to_rgb888_toio(dst, dst_pitch, vmap, fb, clip); + drm_fb_xrgb8888_to_rgb888(dst, dst_pitch, src, fb, clip); return 0; } } else if (dst_format == DRM_FORMAT_XRGB8888) { if (fb_format == DRM_FORMAT_RGB888) { - drm_fb_rgb888_to_xrgb8888_toio(dst, dst_pitch, vmap, fb, clip); + drm_fb_rgb888_to_xrgb8888(dst, dst_pitch, src, fb, clip); return 0; } else if (fb_format == DRM_FORMAT_RGB565) { - drm_fb_rgb565_to_xrgb8888_toio(dst, dst_pitch, vmap, fb, clip); + drm_fb_rgb565_to_xrgb8888(dst, dst_pitch, src, fb, clip); return 0; } } else if (dst_format == DRM_FORMAT_XRGB2101010) { if (fb_format == DRM_FORMAT_XRGB8888) { - drm_fb_xrgb8888_to_xrgb2101010_toio(dst, dst_pitch, vmap, fb, clip); + drm_fb_xrgb8888_to_xrgb2101010(dst, dst_pitch, src, fb, clip); return 0; } } @@ -600,8 +684,7 @@ int drm_fb_blit_toio(void __iomem *dst, unsigned int dst_pitch, uint32_t dst_for return -EINVAL; } -EXPORT_SYMBOL(drm_fb_blit_toio); - +EXPORT_SYMBOL(drm_fb_blit); static void drm_fb_gray8_to_mono_line(void *dbuf, const void *sbuf, unsigned int pixels) { @@ -622,49 +705,67 @@ static void drm_fb_gray8_to_mono_line(void *dbuf, const void *sbuf, unsigned int /** * drm_fb_xrgb8888_to_mono - Convert XRGB8888 to monochrome - * @dst: monochrome destination buffer (0=black, 1=white) - * @dst_pitch: Number of bytes between two consecutive scanlines within dst - * @vaddr: XRGB8888 source buffer + * @dst: Array of monochrome destination buffers (0=black, 1=white) + * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines + * within @dst; can be NULL if scanlines are stored next to each other. + * @src: Array of XRGB8888 source buffers * @fb: DRM framebuffer * @clip: Clip rectangle area to copy * - * DRM doesn't have native monochrome support. - * Such drivers can announce the commonly supported XR24 format to userspace - * and use this function to convert to the native format. + * This function copies parts of a framebuffer to display memory and converts the + * color format during the process. Destination and framebuffer formats must match. The + * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at + * least as many entries as there are planes in @fb's format. Each entry stores the + * value for the format's respective color plane at the same index. + * + * This function does not apply clipping on @dst (i.e. the destination is at the + * top-left corner). The first pixel (upper left corner of the clip rectangle) will + * be converted and copied to the first bit (LSB) in the first byte of the monochrome + * destination buffer. If the caller requires that the first pixel in a byte must + * be located at an x-coordinate that is a multiple of 8, then the caller must take + * care itself of supplying a suitable clip rectangle. + * + * DRM doesn't have native monochrome support. Drivers can use this function for + * monochrome devices that don't support XRGB8888 natively. Such drivers can + * announce the commonly supported XR24 format to userspace and use this function + * to convert to the native format. * * This function uses drm_fb_xrgb8888_to_gray8() to convert to grayscale and * then the result is converted from grayscale to monochrome. - * - * The first pixel (upper left corner of the clip rectangle) will be converted - * and copied to the first bit (LSB) in the first byte of the monochrome - * destination buffer. - * If the caller requires that the first pixel in a byte must be located at an - * x-coordinate that is a multiple of 8, then the caller must take care itself - * of supplying a suitable clip rectangle. */ -void drm_fb_xrgb8888_to_mono(void *dst, unsigned int dst_pitch, const void *vaddr, - const struct drm_framebuffer *fb, const struct drm_rect *clip) +void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitch, + const struct iosys_map *src, const struct drm_framebuffer *fb, + const struct drm_rect *clip) { + static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = { + 0, 0, 0, 0 + }; unsigned int linepixels = drm_rect_width(clip); unsigned int lines = drm_rect_height(clip); unsigned int cpp = fb->format->cpp[0]; unsigned int len_src32 = linepixels * cpp; struct drm_device *dev = fb->dev; + void *vaddr = src[0].vaddr; + unsigned int dst_pitch_0; unsigned int y; - u8 *mono = dst, *gray8; + u8 *mono = dst[0].vaddr, *gray8; u32 *src32; if (drm_WARN_ON(dev, fb->format->format != DRM_FORMAT_XRGB8888)) return; + if (!dst_pitch) + dst_pitch = default_dst_pitch; + dst_pitch_0 = dst_pitch[0]; + /* * The mono destination buffer contains 1 bit per pixel */ - if (!dst_pitch) - dst_pitch = DIV_ROUND_UP(linepixels, 8); + if (!dst_pitch_0) + dst_pitch_0 = DIV_ROUND_UP(linepixels, 8); /* - * The cma memory is write-combined so reads are uncached. + * The dma memory is write-combined so reads are uncached. * Speed up by fetching one line at a time. * * Also, format conversion from XR24 to monochrome are done @@ -686,7 +787,7 @@ void drm_fb_xrgb8888_to_mono(void *dst, unsigned int dst_pitch, const void *vadd drm_fb_xrgb8888_to_gray8_line(gray8, src32, linepixels); drm_fb_gray8_to_mono_line(mono, gray8, linepixels); vaddr += fb->pitches[0]; - mono += dst_pitch; + mono += dst_pitch_0; } kfree(src32); diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index 07741b678798..e09331bb3bc7 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -43,6 +43,21 @@ uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) uint32_t fmt = DRM_FORMAT_INVALID; switch (bpp) { + case 1: + if (depth == 1) + fmt = DRM_FORMAT_C1; + break; + + case 2: + if (depth == 2) + fmt = DRM_FORMAT_C2; + break; + + case 4: + if (depth == 4) + fmt = DRM_FORMAT_C4; + break; + case 8: if (depth == 8) fmt = DRM_FORMAT_C8; @@ -132,7 +147,26 @@ EXPORT_SYMBOL(drm_driver_legacy_fb_format); const struct drm_format_info *__drm_format_info(u32 format) { static const struct drm_format_info formats[] = { - { .format = DRM_FORMAT_C8, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_C1, .depth = 1, .num_planes = 1, + .char_per_block = { 1, }, .block_w = { 8, }, .block_h = { 1, }, .hsub = 1, .vsub = 1, .is_color_indexed = true }, + { .format = DRM_FORMAT_C2, .depth = 2, .num_planes = 1, + .char_per_block = { 1, }, .block_w = { 4, }, .block_h = { 1, }, .hsub = 1, .vsub = 1, .is_color_indexed = true }, + { .format = DRM_FORMAT_C4, .depth = 4, .num_planes = 1, + .char_per_block = { 1, }, .block_w = { 2, }, .block_h = { 1, }, .hsub = 1, .vsub = 1, .is_color_indexed = true }, + { .format = DRM_FORMAT_C8, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1, .is_color_indexed = true }, + { .format = DRM_FORMAT_D1, .depth = 1, .num_planes = 1, + .char_per_block = { 1, }, .block_w = { 8, }, .block_h = { 1, }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_D2, .depth = 2, .num_planes = 1, + .char_per_block = { 1, }, .block_w = { 4, }, .block_h = { 1, }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_D4, .depth = 4, .num_planes = 1, + .char_per_block = { 1, }, .block_w = { 2, }, .block_h = { 1, }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_D8, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_R1, .depth = 1, .num_planes = 1, + .char_per_block = { 1, }, .block_w = { 8, }, .block_h = { 1, }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_R2, .depth = 2, .num_planes = 1, + .char_per_block = { 1, }, .block_w = { 4, }, .block_h = { 1, }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_R4, .depth = 4, .num_planes = 1, + .char_per_block = { 1, }, .block_w = { 2, }, .block_h = { 1, }, .hsub = 1, .vsub = 1 }, { .format = DRM_FORMAT_R8, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 }, { .format = DRM_FORMAT_R10, .depth = 10, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, { .format = DRM_FORMAT_R12, .depth = 12, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, @@ -371,6 +405,25 @@ unsigned int drm_format_info_block_height(const struct drm_format_info *info, EXPORT_SYMBOL(drm_format_info_block_height); /** + * drm_format_info_bpp - number of bits per pixel + * @info: pixel format info + * @plane: plane index + * + * Returns: + * The actual number of bits per pixel, depending on the plane index. + */ +unsigned int drm_format_info_bpp(const struct drm_format_info *info, int plane) +{ + if (!info || plane < 0 || plane >= info->num_planes) + return 0; + + return info->char_per_block[plane] * 8 / + (drm_format_info_block_width(info, plane) * + drm_format_info_block_height(info, plane)); +} +EXPORT_SYMBOL(drm_format_info_bpp); + +/** * drm_format_info_min_pitch - computes the minimum required pitch in bytes * @info: pixel format info * @plane: plane index diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 4562a8b86579..185b04762e2c 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -530,7 +530,7 @@ int drm_mode_getfb(struct drm_device *dev, r->height = fb->height; r->width = fb->width; r->depth = fb->format->depth; - r->bpp = fb->format->cpp[0] * 8; + r->bpp = drm_format_info_bpp(fb->format, 0); r->pitch = fb->pitches[0]; /* GET_FB() is an unprivileged ioctl so we must not return a @@ -935,7 +935,7 @@ EXPORT_SYMBOL(drm_framebuffer_unregister_private); * the id and get back -EINVAL. Obviously no concern at driver unload time. * * Also, the framebuffer will not be removed from the lookup idr - for - * user-created framebuffers this will happen in in the rmfb ioctl. For + * user-created framebuffers this will happen in the rmfb ioctl. For * driver-private objects (e.g. for fbdev) drivers need to explicitly call * drm_framebuffer_unregister_private. */ diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_dma_helper.c index 42abee9a0f4f..f6901ff97bbb 100644 --- a/drivers/gpu/drm/drm_gem_cma_helper.c +++ b/drivers/gpu/drm/drm_gem_dma_helper.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * drm gem CMA (contiguous memory allocator) helper functions + * drm gem DMA helper functions * * Copyright (C) 2012 Sascha Hauer, Pengutronix * @@ -20,20 +20,17 @@ #include <drm/drm.h> #include <drm/drm_device.h> #include <drm/drm_drv.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_vma_manager.h> /** - * DOC: cma helpers + * DOC: dma helpers * - * The DRM GEM/CMA helpers are a means to provide buffer objects that are + * The DRM GEM/DMA helpers are a means to provide buffer objects that are * presented to the device as a contiguous chunk of memory. This is useful * for devices that do not support scatter-gather DMA (either directly or * by using an intimately attached IOMMU). * - * Despite the name, the DRM GEM/CMA helpers are not hardwired to use the - * Contiguous Memory Allocator (CMA). - * * For devices that access the memory bus through an (external) IOMMU then * the buffer objects are allocated using a traditional page-based * allocator and may be scattered through physical memory. However they @@ -44,36 +41,36 @@ * objects that are physically contiguous in memory. * * For GEM callback helpers in struct &drm_gem_object functions, see likewise - * named functions with an _object_ infix (e.g., drm_gem_cma_object_vmap() wraps - * drm_gem_cma_vmap()). These helpers perform the necessary type conversion. + * named functions with an _object_ infix (e.g., drm_gem_dma_object_vmap() wraps + * drm_gem_dma_vmap()). These helpers perform the necessary type conversion. */ -static const struct drm_gem_object_funcs drm_gem_cma_default_funcs = { - .free = drm_gem_cma_object_free, - .print_info = drm_gem_cma_object_print_info, - .get_sg_table = drm_gem_cma_object_get_sg_table, - .vmap = drm_gem_cma_object_vmap, - .mmap = drm_gem_cma_object_mmap, - .vm_ops = &drm_gem_cma_vm_ops, +static const struct drm_gem_object_funcs drm_gem_dma_default_funcs = { + .free = drm_gem_dma_object_free, + .print_info = drm_gem_dma_object_print_info, + .get_sg_table = drm_gem_dma_object_get_sg_table, + .vmap = drm_gem_dma_object_vmap, + .mmap = drm_gem_dma_object_mmap, + .vm_ops = &drm_gem_dma_vm_ops, }; /** - * __drm_gem_cma_create - Create a GEM CMA object without allocating memory + * __drm_gem_dma_create - Create a GEM DMA object without allocating memory * @drm: DRM device * @size: size of the object to allocate * @private: true if used for internal purposes * - * This function creates and initializes a GEM CMA object of the given size, + * This function creates and initializes a GEM DMA object of the given size, * but doesn't allocate any memory to back the object. * * Returns: - * A struct drm_gem_cma_object * on success or an ERR_PTR()-encoded negative + * A struct drm_gem_dma_object * on success or an ERR_PTR()-encoded negative * error code on failure. */ -static struct drm_gem_cma_object * -__drm_gem_cma_create(struct drm_device *drm, size_t size, bool private) +static struct drm_gem_dma_object * +__drm_gem_dma_create(struct drm_device *drm, size_t size, bool private) { - struct drm_gem_cma_object *cma_obj; + struct drm_gem_dma_object *dma_obj; struct drm_gem_object *gem_obj; int ret = 0; @@ -81,22 +78,22 @@ __drm_gem_cma_create(struct drm_device *drm, size_t size, bool private) gem_obj = drm->driver->gem_create_object(drm, size); if (IS_ERR(gem_obj)) return ERR_CAST(gem_obj); - cma_obj = to_drm_gem_cma_obj(gem_obj); + dma_obj = to_drm_gem_dma_obj(gem_obj); } else { - cma_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL); - if (!cma_obj) + dma_obj = kzalloc(sizeof(*dma_obj), GFP_KERNEL); + if (!dma_obj) return ERR_PTR(-ENOMEM); - gem_obj = &cma_obj->base; + gem_obj = &dma_obj->base; } if (!gem_obj->funcs) - gem_obj->funcs = &drm_gem_cma_default_funcs; + gem_obj->funcs = &drm_gem_dma_default_funcs; if (private) { drm_gem_private_object_init(drm, gem_obj, size); /* Always use writecombine for dma-buf mappings */ - cma_obj->map_noncoherent = false; + dma_obj->map_noncoherent = false; } else { ret = drm_gem_object_init(drm, gem_obj, size); } @@ -109,19 +106,19 @@ __drm_gem_cma_create(struct drm_device *drm, size_t size, bool private) goto error; } - return cma_obj; + return dma_obj; error: - kfree(cma_obj); + kfree(dma_obj); return ERR_PTR(ret); } /** - * drm_gem_cma_create - allocate an object with the given size + * drm_gem_dma_create - allocate an object with the given size * @drm: DRM device * @size: size of the object to allocate * - * This function creates a CMA GEM object and allocates memory as backing store. + * This function creates a DMA GEM object and allocates memory as backing store. * The allocated memory will occupy a contiguous chunk of bus address space. * * For devices that are directly connected to the memory bus then the allocated @@ -131,78 +128,79 @@ error: * requirements. * * Returns: - * A struct drm_gem_cma_object * on success or an ERR_PTR()-encoded negative + * A struct drm_gem_dma_object * on success or an ERR_PTR()-encoded negative * error code on failure. */ -struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm, +struct drm_gem_dma_object *drm_gem_dma_create(struct drm_device *drm, size_t size) { - struct drm_gem_cma_object *cma_obj; + struct drm_gem_dma_object *dma_obj; int ret; size = round_up(size, PAGE_SIZE); - cma_obj = __drm_gem_cma_create(drm, size, false); - if (IS_ERR(cma_obj)) - return cma_obj; + dma_obj = __drm_gem_dma_create(drm, size, false); + if (IS_ERR(dma_obj)) + return dma_obj; - if (cma_obj->map_noncoherent) { - cma_obj->vaddr = dma_alloc_noncoherent(drm->dev, size, - &cma_obj->paddr, + if (dma_obj->map_noncoherent) { + dma_obj->vaddr = dma_alloc_noncoherent(drm->dev, size, + &dma_obj->dma_addr, DMA_TO_DEVICE, GFP_KERNEL | __GFP_NOWARN); } else { - cma_obj->vaddr = dma_alloc_wc(drm->dev, size, &cma_obj->paddr, + dma_obj->vaddr = dma_alloc_wc(drm->dev, size, + &dma_obj->dma_addr, GFP_KERNEL | __GFP_NOWARN); } - if (!cma_obj->vaddr) { + if (!dma_obj->vaddr) { drm_dbg(drm, "failed to allocate buffer with size %zu\n", size); ret = -ENOMEM; goto error; } - return cma_obj; + return dma_obj; error: - drm_gem_object_put(&cma_obj->base); + drm_gem_object_put(&dma_obj->base); return ERR_PTR(ret); } -EXPORT_SYMBOL_GPL(drm_gem_cma_create); +EXPORT_SYMBOL_GPL(drm_gem_dma_create); /** - * drm_gem_cma_create_with_handle - allocate an object with the given size and + * drm_gem_dma_create_with_handle - allocate an object with the given size and * return a GEM handle to it * @file_priv: DRM file-private structure to register the handle for * @drm: DRM device * @size: size of the object to allocate * @handle: return location for the GEM handle * - * This function creates a CMA GEM object, allocating a chunk of memory as + * This function creates a DMA GEM object, allocating a chunk of memory as * backing store. The GEM object is then added to the list of object associated * with the given file and a handle to it is returned. * * The allocated memory will occupy a contiguous chunk of bus address space. - * See drm_gem_cma_create() for more details. + * See drm_gem_dma_create() for more details. * * Returns: - * A struct drm_gem_cma_object * on success or an ERR_PTR()-encoded negative + * A struct drm_gem_dma_object * on success or an ERR_PTR()-encoded negative * error code on failure. */ -static struct drm_gem_cma_object * -drm_gem_cma_create_with_handle(struct drm_file *file_priv, +static struct drm_gem_dma_object * +drm_gem_dma_create_with_handle(struct drm_file *file_priv, struct drm_device *drm, size_t size, uint32_t *handle) { - struct drm_gem_cma_object *cma_obj; + struct drm_gem_dma_object *dma_obj; struct drm_gem_object *gem_obj; int ret; - cma_obj = drm_gem_cma_create(drm, size); - if (IS_ERR(cma_obj)) - return cma_obj; + dma_obj = drm_gem_dma_create(drm, size); + if (IS_ERR(dma_obj)) + return dma_obj; - gem_obj = &cma_obj->base; + gem_obj = &dma_obj->base; /* * allocate a id of idr table where the obj is registered @@ -214,44 +212,44 @@ drm_gem_cma_create_with_handle(struct drm_file *file_priv, if (ret) return ERR_PTR(ret); - return cma_obj; + return dma_obj; } /** - * drm_gem_cma_free - free resources associated with a CMA GEM object - * @cma_obj: CMA GEM object to free + * drm_gem_dma_free - free resources associated with a DMA GEM object + * @dma_obj: DMA GEM object to free * - * This function frees the backing memory of the CMA GEM object, cleans up the + * This function frees the backing memory of the DMA GEM object, cleans up the * GEM object state and frees the memory used to store the object itself. * If the buffer is imported and the virtual address is set, it is released. */ -void drm_gem_cma_free(struct drm_gem_cma_object *cma_obj) +void drm_gem_dma_free(struct drm_gem_dma_object *dma_obj) { - struct drm_gem_object *gem_obj = &cma_obj->base; - struct iosys_map map = IOSYS_MAP_INIT_VADDR(cma_obj->vaddr); + struct drm_gem_object *gem_obj = &dma_obj->base; + struct iosys_map map = IOSYS_MAP_INIT_VADDR(dma_obj->vaddr); if (gem_obj->import_attach) { - if (cma_obj->vaddr) + if (dma_obj->vaddr) dma_buf_vunmap(gem_obj->import_attach->dmabuf, &map); - drm_prime_gem_destroy(gem_obj, cma_obj->sgt); - } else if (cma_obj->vaddr) { - if (cma_obj->map_noncoherent) - dma_free_noncoherent(gem_obj->dev->dev, cma_obj->base.size, - cma_obj->vaddr, cma_obj->paddr, + drm_prime_gem_destroy(gem_obj, dma_obj->sgt); + } else if (dma_obj->vaddr) { + if (dma_obj->map_noncoherent) + dma_free_noncoherent(gem_obj->dev->dev, dma_obj->base.size, + dma_obj->vaddr, dma_obj->dma_addr, DMA_TO_DEVICE); else - dma_free_wc(gem_obj->dev->dev, cma_obj->base.size, - cma_obj->vaddr, cma_obj->paddr); + dma_free_wc(gem_obj->dev->dev, dma_obj->base.size, + dma_obj->vaddr, dma_obj->dma_addr); } drm_gem_object_release(gem_obj); - kfree(cma_obj); + kfree(dma_obj); } -EXPORT_SYMBOL_GPL(drm_gem_cma_free); +EXPORT_SYMBOL_GPL(drm_gem_dma_free); /** - * drm_gem_cma_dumb_create_internal - create a dumb buffer object + * drm_gem_dma_dumb_create_internal - create a dumb buffer object * @file_priv: DRM file-private structure to create the dumb buffer for * @drm: DRM device * @args: IOCTL data @@ -264,12 +262,12 @@ EXPORT_SYMBOL_GPL(drm_gem_cma_free); * Returns: * 0 on success or a negative error code on failure. */ -int drm_gem_cma_dumb_create_internal(struct drm_file *file_priv, +int drm_gem_dma_dumb_create_internal(struct drm_file *file_priv, struct drm_device *drm, struct drm_mode_create_dumb *args) { unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); - struct drm_gem_cma_object *cma_obj; + struct drm_gem_dma_object *dma_obj; if (args->pitch < min_pitch) args->pitch = min_pitch; @@ -277,14 +275,14 @@ int drm_gem_cma_dumb_create_internal(struct drm_file *file_priv, if (args->size < args->pitch * args->height) args->size = args->pitch * args->height; - cma_obj = drm_gem_cma_create_with_handle(file_priv, drm, args->size, + dma_obj = drm_gem_dma_create_with_handle(file_priv, drm, args->size, &args->handle); - return PTR_ERR_OR_ZERO(cma_obj); + return PTR_ERR_OR_ZERO(dma_obj); } -EXPORT_SYMBOL_GPL(drm_gem_cma_dumb_create_internal); +EXPORT_SYMBOL_GPL(drm_gem_dma_dumb_create_internal); /** - * drm_gem_cma_dumb_create - create a dumb buffer object + * drm_gem_dma_dumb_create - create a dumb buffer object * @file_priv: DRM file-private structure to create the dumb buffer for * @drm: DRM device * @args: IOCTL data @@ -296,35 +294,35 @@ EXPORT_SYMBOL_GPL(drm_gem_cma_dumb_create_internal); * * For hardware with additional restrictions, drivers can adjust the fields * set up by userspace and pass the IOCTL data along to the - * drm_gem_cma_dumb_create_internal() function. + * drm_gem_dma_dumb_create_internal() function. * * Returns: * 0 on success or a negative error code on failure. */ -int drm_gem_cma_dumb_create(struct drm_file *file_priv, +int drm_gem_dma_dumb_create(struct drm_file *file_priv, struct drm_device *drm, struct drm_mode_create_dumb *args) { - struct drm_gem_cma_object *cma_obj; + struct drm_gem_dma_object *dma_obj; args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8); args->size = args->pitch * args->height; - cma_obj = drm_gem_cma_create_with_handle(file_priv, drm, args->size, + dma_obj = drm_gem_dma_create_with_handle(file_priv, drm, args->size, &args->handle); - return PTR_ERR_OR_ZERO(cma_obj); + return PTR_ERR_OR_ZERO(dma_obj); } -EXPORT_SYMBOL_GPL(drm_gem_cma_dumb_create); +EXPORT_SYMBOL_GPL(drm_gem_dma_dumb_create); -const struct vm_operations_struct drm_gem_cma_vm_ops = { +const struct vm_operations_struct drm_gem_dma_vm_ops = { .open = drm_gem_vm_open, .close = drm_gem_vm_close, }; -EXPORT_SYMBOL_GPL(drm_gem_cma_vm_ops); +EXPORT_SYMBOL_GPL(drm_gem_dma_vm_ops); #ifndef CONFIG_MMU /** - * drm_gem_cma_get_unmapped_area - propose address for mapping in noMMU cases + * drm_gem_dma_get_unmapped_area - propose address for mapping in noMMU cases * @filp: file object * @addr: memory address * @len: buffer size @@ -339,13 +337,13 @@ EXPORT_SYMBOL_GPL(drm_gem_cma_vm_ops); * Returns: * mapping address on success or a negative error code on failure. */ -unsigned long drm_gem_cma_get_unmapped_area(struct file *filp, +unsigned long drm_gem_dma_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { - struct drm_gem_cma_object *cma_obj; + struct drm_gem_dma_object *dma_obj; struct drm_gem_object *obj = NULL; struct drm_file *priv = filp->private_data; struct drm_device *dev = priv->minor->dev; @@ -384,35 +382,35 @@ unsigned long drm_gem_cma_get_unmapped_area(struct file *filp, return -EACCES; } - cma_obj = to_drm_gem_cma_obj(obj); + dma_obj = to_drm_gem_dma_obj(obj); drm_gem_object_put(obj); - return cma_obj->vaddr ? (unsigned long)cma_obj->vaddr : -EINVAL; + return dma_obj->vaddr ? (unsigned long)dma_obj->vaddr : -EINVAL; } -EXPORT_SYMBOL_GPL(drm_gem_cma_get_unmapped_area); +EXPORT_SYMBOL_GPL(drm_gem_dma_get_unmapped_area); #endif /** - * drm_gem_cma_print_info() - Print &drm_gem_cma_object info for debugfs - * @cma_obj: CMA GEM object + * drm_gem_dma_print_info() - Print &drm_gem_dma_object info for debugfs + * @dma_obj: DMA GEM object * @p: DRM printer * @indent: Tab indentation level * - * This function prints paddr and vaddr for use in e.g. debugfs output. + * This function prints dma_addr and vaddr for use in e.g. debugfs output. */ -void drm_gem_cma_print_info(const struct drm_gem_cma_object *cma_obj, +void drm_gem_dma_print_info(const struct drm_gem_dma_object *dma_obj, struct drm_printer *p, unsigned int indent) { - drm_printf_indent(p, indent, "paddr=%pad\n", &cma_obj->paddr); - drm_printf_indent(p, indent, "vaddr=%p\n", cma_obj->vaddr); + drm_printf_indent(p, indent, "dma_addr=%pad\n", &dma_obj->dma_addr); + drm_printf_indent(p, indent, "vaddr=%p\n", dma_obj->vaddr); } -EXPORT_SYMBOL(drm_gem_cma_print_info); +EXPORT_SYMBOL(drm_gem_dma_print_info); /** - * drm_gem_cma_get_sg_table - provide a scatter/gather table of pinned - * pages for a CMA GEM object - * @cma_obj: CMA GEM object + * drm_gem_dma_get_sg_table - provide a scatter/gather table of pinned + * pages for a DMA GEM object + * @dma_obj: DMA GEM object * * This function exports a scatter/gather table by calling the standard * DMA mapping API. @@ -420,9 +418,9 @@ EXPORT_SYMBOL(drm_gem_cma_print_info); * Returns: * A pointer to the scatter/gather table of pinned pages or NULL on failure. */ -struct sg_table *drm_gem_cma_get_sg_table(struct drm_gem_cma_object *cma_obj) +struct sg_table *drm_gem_dma_get_sg_table(struct drm_gem_dma_object *dma_obj) { - struct drm_gem_object *obj = &cma_obj->base; + struct drm_gem_object *obj = &dma_obj->base; struct sg_table *sgt; int ret; @@ -430,8 +428,8 @@ struct sg_table *drm_gem_cma_get_sg_table(struct drm_gem_cma_object *cma_obj) if (!sgt) return ERR_PTR(-ENOMEM); - ret = dma_get_sgtable(obj->dev->dev, sgt, cma_obj->vaddr, - cma_obj->paddr, obj->size); + ret = dma_get_sgtable(obj->dev->dev, sgt, dma_obj->vaddr, + dma_obj->dma_addr, obj->size); if (ret < 0) goto out; @@ -441,10 +439,10 @@ out: kfree(sgt); return ERR_PTR(ret); } -EXPORT_SYMBOL_GPL(drm_gem_cma_get_sg_table); +EXPORT_SYMBOL_GPL(drm_gem_dma_get_sg_table); /** - * drm_gem_cma_prime_import_sg_table - produce a CMA GEM object from another + * drm_gem_dma_prime_import_sg_table - produce a DMA GEM object from another * driver's scatter/gather table of pinned pages * @dev: device to import into * @attach: DMA-BUF attachment @@ -453,7 +451,7 @@ EXPORT_SYMBOL_GPL(drm_gem_cma_get_sg_table); * This function imports a scatter/gather table exported via DMA-BUF by * another driver. Imported buffers must be physically contiguous in memory * (i.e. the scatter/gather table must contain a single entry). Drivers that - * use the CMA helpers should set this as their + * use the DMA helpers should set this as their * &drm_driver.gem_prime_import_sg_table callback. * * Returns: @@ -461,56 +459,57 @@ EXPORT_SYMBOL_GPL(drm_gem_cma_get_sg_table); * error code on failure. */ struct drm_gem_object * -drm_gem_cma_prime_import_sg_table(struct drm_device *dev, +drm_gem_dma_prime_import_sg_table(struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sgt) { - struct drm_gem_cma_object *cma_obj; + struct drm_gem_dma_object *dma_obj; /* check if the entries in the sg_table are contiguous */ if (drm_prime_get_contiguous_size(sgt) < attach->dmabuf->size) return ERR_PTR(-EINVAL); - /* Create a CMA GEM buffer. */ - cma_obj = __drm_gem_cma_create(dev, attach->dmabuf->size, true); - if (IS_ERR(cma_obj)) - return ERR_CAST(cma_obj); + /* Create a DMA GEM buffer. */ + dma_obj = __drm_gem_dma_create(dev, attach->dmabuf->size, true); + if (IS_ERR(dma_obj)) + return ERR_CAST(dma_obj); - cma_obj->paddr = sg_dma_address(sgt->sgl); - cma_obj->sgt = sgt; + dma_obj->dma_addr = sg_dma_address(sgt->sgl); + dma_obj->sgt = sgt; - DRM_DEBUG_PRIME("dma_addr = %pad, size = %zu\n", &cma_obj->paddr, attach->dmabuf->size); + DRM_DEBUG_PRIME("dma_addr = %pad, size = %zu\n", &dma_obj->dma_addr, + attach->dmabuf->size); - return &cma_obj->base; + return &dma_obj->base; } -EXPORT_SYMBOL_GPL(drm_gem_cma_prime_import_sg_table); +EXPORT_SYMBOL_GPL(drm_gem_dma_prime_import_sg_table); /** - * drm_gem_cma_vmap - map a CMA GEM object into the kernel's virtual + * drm_gem_dma_vmap - map a DMA GEM object into the kernel's virtual * address space - * @cma_obj: CMA GEM object - * @map: Returns the kernel virtual address of the CMA GEM object's backing + * @dma_obj: DMA GEM object + * @map: Returns the kernel virtual address of the DMA GEM object's backing * store. * * This function maps a buffer into the kernel's virtual address space. - * Since the CMA buffers are already mapped into the kernel virtual address + * Since the DMA buffers are already mapped into the kernel virtual address * space this simply returns the cached virtual address. * * Returns: * 0 on success, or a negative error code otherwise. */ -int drm_gem_cma_vmap(struct drm_gem_cma_object *cma_obj, +int drm_gem_dma_vmap(struct drm_gem_dma_object *dma_obj, struct iosys_map *map) { - iosys_map_set_vaddr(map, cma_obj->vaddr); + iosys_map_set_vaddr(map, dma_obj->vaddr); return 0; } -EXPORT_SYMBOL_GPL(drm_gem_cma_vmap); +EXPORT_SYMBOL_GPL(drm_gem_dma_vmap); /** - * drm_gem_cma_mmap - memory-map an exported CMA GEM object - * @cma_obj: CMA GEM object + * drm_gem_dma_mmap - memory-map an exported DMA GEM object + * @dma_obj: DMA GEM object * @vma: VMA for the area to be mapped * * This function maps a buffer into a userspace process's address space. @@ -520,9 +519,9 @@ EXPORT_SYMBOL_GPL(drm_gem_cma_vmap); * Returns: * 0 on success or a negative error code on failure. */ -int drm_gem_cma_mmap(struct drm_gem_cma_object *cma_obj, struct vm_area_struct *vma) +int drm_gem_dma_mmap(struct drm_gem_dma_object *dma_obj, struct vm_area_struct *vma) { - struct drm_gem_object *obj = &cma_obj->base; + struct drm_gem_object *obj = &dma_obj->base; int ret; /* @@ -534,37 +533,38 @@ int drm_gem_cma_mmap(struct drm_gem_cma_object *cma_obj, struct vm_area_struct * vma->vm_flags &= ~VM_PFNMAP; vma->vm_flags |= VM_DONTEXPAND; - if (cma_obj->map_noncoherent) { + if (dma_obj->map_noncoherent) { vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); - ret = dma_mmap_pages(cma_obj->base.dev->dev, + ret = dma_mmap_pages(dma_obj->base.dev->dev, vma, vma->vm_end - vma->vm_start, - virt_to_page(cma_obj->vaddr)); + virt_to_page(dma_obj->vaddr)); } else { - ret = dma_mmap_wc(cma_obj->base.dev->dev, vma, cma_obj->vaddr, - cma_obj->paddr, vma->vm_end - vma->vm_start); + ret = dma_mmap_wc(dma_obj->base.dev->dev, vma, dma_obj->vaddr, + dma_obj->dma_addr, + vma->vm_end - vma->vm_start); } if (ret) drm_gem_vm_close(vma); return ret; } -EXPORT_SYMBOL_GPL(drm_gem_cma_mmap); +EXPORT_SYMBOL_GPL(drm_gem_dma_mmap); /** - * drm_gem_cma_prime_import_sg_table_vmap - PRIME import another driver's + * drm_gem_dma_prime_import_sg_table_vmap - PRIME import another driver's * scatter/gather table and get the virtual address of the buffer * @dev: DRM device * @attach: DMA-BUF attachment * @sgt: Scatter/gather table of pinned pages * * This function imports a scatter/gather table using - * drm_gem_cma_prime_import_sg_table() and uses dma_buf_vmap() to get the kernel - * virtual address. This ensures that a CMA GEM object always has its virtual + * drm_gem_dma_prime_import_sg_table() and uses dma_buf_vmap() to get the kernel + * virtual address. This ensures that a DMA GEM object always has its virtual * address set. This address is released when the object is freed. * * This function can be used as the &drm_driver.gem_prime_import_sg_table - * callback. The &DRM_GEM_CMA_DRIVER_OPS_VMAP macro provides a shortcut to set + * callback. The &DRM_GEM_DMA_DRIVER_OPS_VMAP macro provides a shortcut to set * the necessary DRM driver operations. * * Returns: @@ -572,11 +572,11 @@ EXPORT_SYMBOL_GPL(drm_gem_cma_mmap); * error code on failure. */ struct drm_gem_object * -drm_gem_cma_prime_import_sg_table_vmap(struct drm_device *dev, +drm_gem_dma_prime_import_sg_table_vmap(struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sgt) { - struct drm_gem_cma_object *cma_obj; + struct drm_gem_dma_object *dma_obj; struct drm_gem_object *obj; struct iosys_map map; int ret; @@ -587,19 +587,19 @@ drm_gem_cma_prime_import_sg_table_vmap(struct drm_device *dev, return ERR_PTR(ret); } - obj = drm_gem_cma_prime_import_sg_table(dev, attach, sgt); + obj = drm_gem_dma_prime_import_sg_table(dev, attach, sgt); if (IS_ERR(obj)) { dma_buf_vunmap(attach->dmabuf, &map); return obj; } - cma_obj = to_drm_gem_cma_obj(obj); - cma_obj->vaddr = map.vaddr; + dma_obj = to_drm_gem_dma_obj(obj); + dma_obj->vaddr = map.vaddr; return obj; } -EXPORT_SYMBOL(drm_gem_cma_prime_import_sg_table_vmap); +EXPORT_SYMBOL(drm_gem_dma_prime_import_sg_table_vmap); -MODULE_DESCRIPTION("DRM CMA memory-management helpers"); +MODULE_DESCRIPTION("DRM DMA memory-management helpers"); MODULE_IMPORT_NS(DMA_BUF); MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index 61339a9cd010..880a4975507f 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -490,6 +490,8 @@ void drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_directi } EXPORT_SYMBOL(drm_gem_fb_end_cpu_access); +// TODO Drop this function and replace by drm_format_info_bpp() once all +// DRM_FORMAT_* provide proper block info in drivers/gpu/drm/drm_fourcc.c static __u32 drm_gem_afbc_get_bpp(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd) { @@ -497,11 +499,6 @@ static __u32 drm_gem_afbc_get_bpp(struct drm_device *dev, info = drm_get_format_info(dev, mode_cmd); - /* use whatever a driver has set */ - if (info->cpp[0]) - return info->cpp[0] * 8; - - /* guess otherwise */ switch (info->format) { case DRM_FORMAT_YUV420_8BIT: return 12; @@ -510,11 +507,8 @@ static __u32 drm_gem_afbc_get_bpp(struct drm_device *dev, case DRM_FORMAT_VUY101010: return 30; default: - break; + return drm_format_info_bpp(info, 0); } - - /* all attempts failed */ - return 0; } static int drm_gem_afbc_min_size(struct drm_device *dev, diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c index 904fc893c905..35138f8a375c 100644 --- a/drivers/gpu/drm/drm_gem_shmem_helper.c +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c @@ -663,7 +663,7 @@ EXPORT_SYMBOL(drm_gem_shmem_print_info); * drm_gem_shmem_get_pages_sgt() instead. * * Returns: - * A pointer to the scatter/gather table of pinned pages or NULL on failure. + * A pointer to the scatter/gather table of pinned pages or error pointer on failure. */ struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_shmem_object *shmem) { diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c index d607043716d3..125160b534be 100644 --- a/drivers/gpu/drm/drm_gem_vram_helper.c +++ b/drivers/gpu/drm/drm_gem_vram_helper.c @@ -226,9 +226,9 @@ struct drm_gem_vram_object *drm_gem_vram_create(struct drm_device *dev, * A failing ttm_bo_init will call ttm_buffer_object_destroy * to release gbo->bo.base and kfree gbo. */ - ret = ttm_bo_init(bdev, &gbo->bo, size, ttm_bo_type_device, - &gbo->placement, pg_align, false, NULL, NULL, - ttm_buffer_object_destroy); + ret = ttm_bo_init_validate(bdev, &gbo->bo, ttm_bo_type_device, + &gbo->placement, pg_align, false, NULL, NULL, + ttm_buffer_object_destroy); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 8faad23dc1d8..ca2a6e6101dc 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -472,7 +472,13 @@ EXPORT_SYMBOL(drm_invalid_op); */ static int drm_copy_field(char __user *buf, size_t *buf_len, const char *value) { - int len; + size_t len; + + /* don't attempt to copy a NULL pointer */ + if (WARN_ONCE(!value, "BUG: the value to copy was not set!")) { + *buf_len = 0; + return 0; + } /* don't overflow userbuf */ len = strlen(value); diff --git a/drivers/gpu/drm/drm_mipi_dbi.c b/drivers/gpu/drm/drm_mipi_dbi.c index 2f61f53d472f..84abc3920b57 100644 --- a/drivers/gpu/drm/drm_mipi_dbi.c +++ b/drivers/gpu/drm/drm_mipi_dbi.c @@ -205,7 +205,7 @@ int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb, struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0); struct iosys_map map[DRM_FORMAT_MAX_PLANES]; struct iosys_map data[DRM_FORMAT_MAX_PLANES]; - void *src; + struct iosys_map dst_map = IOSYS_MAP_INIT_VADDR(dst); int ret; ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); @@ -215,17 +215,16 @@ int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb, ret = drm_gem_fb_vmap(fb, map, data); if (ret) goto out_drm_gem_fb_end_cpu_access; - src = data[0].vaddr; /* TODO: Use mapping abstraction properly */ switch (fb->format->format) { case DRM_FORMAT_RGB565: if (swap) - drm_fb_swab(dst, 0, src, fb, clip, !gem->import_attach); + drm_fb_swab(&dst_map, NULL, data, fb, clip, !gem->import_attach); else - drm_fb_memcpy(dst, 0, src, fb, clip); + drm_fb_memcpy(&dst_map, NULL, data, fb, clip); break; case DRM_FORMAT_XRGB8888: - drm_fb_xrgb8888_to_rgb565(dst, 0, src, fb, clip, swap); + drm_fb_xrgb8888_to_rgb565(&dst_map, NULL, data, fb, clip, swap); break; default: drm_err_once(fb->dev, "Format is not supported: %p4cc\n", @@ -1136,7 +1135,7 @@ int mipi_dbi_spi_init(struct spi_device *spi, struct mipi_dbi *dbi, /* * Even though it's not the SPI device that does DMA (the master does), * the dma mask is necessary for the dma_alloc_wc() in the GEM code - * (e.g., drm_gem_cma_create()). The dma_addr returned will be a physical + * (e.g., drm_gem_dma_create()). The dma_addr returned will be a physical * address which might be different from the bus address, but this is * not a problem since the address will not be used. * The virtual address is used in the transfer and the SPI core diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index c40bde96cfdf..3ec02748d56f 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -346,6 +346,7 @@ static int mipi_dsi_remove_device_fn(struct device *dev, void *priv) { struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); + mipi_dsi_detach(dsi); mipi_dsi_device_unregister(dsi); return 0; @@ -1236,7 +1237,9 @@ static int mipi_dsi_drv_remove(struct device *dev) struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver); struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); - return drv->remove(dsi); + drv->remove(dsi); + + return 0; } static void mipi_dsi_drv_shutdown(struct device *dev) diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index 59b34f07cfce..688c8afe0bf1 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -412,8 +412,8 @@ int drmm_mode_config_init(struct drm_device *dev) INIT_LIST_HEAD(&dev->mode_config.property_blob_list); INIT_LIST_HEAD(&dev->mode_config.plane_list); INIT_LIST_HEAD(&dev->mode_config.privobj_list); - idr_init(&dev->mode_config.object_idr); - idr_init(&dev->mode_config.tile_idr); + idr_init_base(&dev->mode_config.object_idr, 1); + idr_init_base(&dev->mode_config.tile_idr, 1); ida_init(&dev->mode_config.connector_ida); spin_lock_init(&dev->mode_config.connector_list_lock); diff --git a/drivers/gpu/drm/drm_modeset_helper.c b/drivers/gpu/drm/drm_modeset_helper.c index 0f08319453b2..bd609a978848 100644 --- a/drivers/gpu/drm/drm_modeset_helper.c +++ b/drivers/gpu/drm/drm_modeset_helper.c @@ -108,6 +108,12 @@ static const uint32_t safe_modeset_formats[] = { DRM_FORMAT_ARGB8888, }; +static const struct drm_plane_funcs primary_plane_funcs = { + .update_plane = drm_plane_helper_update_primary, + .disable_plane = drm_plane_helper_disable_primary, + .destroy = drm_plane_helper_destroy, +}; + static struct drm_plane *create_primary_plane(struct drm_device *dev) { struct drm_plane *primary; @@ -127,7 +133,7 @@ static struct drm_plane *create_primary_plane(struct drm_device *dev) /* possible_crtc's will be filled in later by crtc_init */ ret = drm_universal_plane_init(dev, primary, 0, - &drm_primary_helper_funcs, + &primary_plane_funcs, safe_modeset_formats, ARRAY_SIZE(safe_modeset_formats), NULL, diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 838b32b70bce..c7785967f5bf 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -145,13 +145,36 @@ static int drm_plane_helper_check_update(struct drm_plane *plane, return 0; } -static int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, - struct drm_framebuffer *fb, - int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h, - struct drm_modeset_acquire_ctx *ctx) +/** + * drm_plane_helper_update_primary - Helper for updating primary planes + * @plane: plane to update + * @crtc: the plane's new CRTC + * @fb: the plane's new framebuffer + * @crtc_x: x coordinate within CRTC + * @crtc_y: y coordinate within CRTC + * @crtc_w: width coordinate within CRTC + * @crtc_h: height coordinate within CRTC + * @src_x: x coordinate within source + * @src_y: y coordinate within source + * @src_w: width coordinate within source + * @src_h: height coordinate within source + * @ctx: modeset locking context + * + * This helper validates the given parameters and updates the primary plane. + * + * This function is only useful for non-atomic modesetting. Don't use + * it in new drivers. + * + * Returns: + * Zero on success, or an errno code otherwise. + */ +int drm_plane_helper_update_primary(struct drm_plane *plane, struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { struct drm_mode_set set = { .crtc = crtc, @@ -179,8 +202,8 @@ static int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *c ret = drm_plane_helper_check_update(plane, crtc, fb, &src, &dest, DRM_MODE_ROTATE_0, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, false, false, &visible); if (ret) return ret; @@ -218,31 +241,40 @@ static int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *c kfree(connector_list); return ret; } +EXPORT_SYMBOL(drm_plane_helper_update_primary); -static int drm_primary_helper_disable(struct drm_plane *plane, - struct drm_modeset_acquire_ctx *ctx) +/** + * drm_plane_helper_disable_primary - Helper for disabling primary planes + * @plane: plane to disable + * @ctx: modeset locking context + * + * This helper returns an error when trying to disable the primary + * plane. + * + * This function is only useful for non-atomic modesetting. Don't use + * it in new drivers. + * + * Returns: + * An errno code. + */ +int drm_plane_helper_disable_primary(struct drm_plane *plane, + struct drm_modeset_acquire_ctx *ctx) { return -EINVAL; } +EXPORT_SYMBOL(drm_plane_helper_disable_primary); /** - * drm_primary_helper_destroy() - Helper for primary plane destruction + * drm_plane_helper_destroy() - Helper for primary plane destruction * @plane: plane to destroy * * Provides a default plane destroy handler for primary planes. This handler * is called during CRTC destruction. We disable the primary plane, remove * it from the DRM plane list, and deallocate the plane structure. */ -void drm_primary_helper_destroy(struct drm_plane *plane) +void drm_plane_helper_destroy(struct drm_plane *plane) { drm_plane_cleanup(plane); kfree(plane); } -EXPORT_SYMBOL(drm_primary_helper_destroy); - -const struct drm_plane_funcs drm_primary_helper_funcs = { - .update_plane = drm_primary_helper_update, - .disable_plane = drm_primary_helper_disable, - .destroy = drm_primary_helper_destroy, -}; -EXPORT_SYMBOL(drm_primary_helper_funcs); +EXPORT_SYMBOL(drm_plane_helper_destroy); diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c index 36633590ebf3..e9f782119d3d 100644 --- a/drivers/gpu/drm/drm_simple_kms_helper.c +++ b/drivers/gpu/drm/drm_simple_kms_helper.c @@ -12,7 +12,6 @@ #include <drm/drm_drv.h> #include <drm/drm_gem_atomic_helper.h> #include <drm/drm_managed.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_simple_kms_helper.h> @@ -223,8 +222,8 @@ static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane, &pipe->crtc); ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, false, false); if (ret) return ret; diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index 66e5f1e34044..7c3aa77186d3 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -9,7 +9,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_blend.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_plane_helper.h> #include <drm/exynos_drm.h> #include "exynos_drm_crtc.h" diff --git a/drivers/gpu/drm/fsl-dcu/Kconfig b/drivers/gpu/drm/fsl-dcu/Kconfig index e95e96c565ba..5ca71ef87325 100644 --- a/drivers/gpu/drm/fsl-dcu/Kconfig +++ b/drivers/gpu/drm/fsl-dcu/Kconfig @@ -3,7 +3,7 @@ config DRM_FSL_DCU tristate "DRM Support for Freescale DCU" depends on DRM && OF && ARM && COMMON_CLK select BACKLIGHT_CLASS_DEVICE - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_KMS_HELPER select DRM_PANEL select REGMAP_MMIO diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c index 7a503bf08d0f..b4acc3422ba4 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c @@ -20,9 +20,8 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_modeset_helper.h> #include <drm/drm_module.h> #include <drm/drm_probe_helper.h> @@ -150,13 +149,13 @@ static void fsl_dcu_unload(struct drm_device *dev) dev->dev_private = NULL; } -DEFINE_DRM_GEM_CMA_FOPS(fsl_dcu_drm_fops); +DEFINE_DRM_GEM_DMA_FOPS(fsl_dcu_drm_fops); static const struct drm_driver fsl_dcu_drm_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .load = fsl_dcu_load, .unload = fsl_dcu_unload, - DRM_GEM_CMA_DRIVER_OPS, + DRM_GEM_DMA_DRIVER_OPS, .fops = &fsl_dcu_drm_fops, .name = "fsl-dcu-drm", .desc = "Freescale DCU DRM", diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c index d763f53f480c..5b47000738e4 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c @@ -6,7 +6,6 @@ */ #include <drm/drm_atomic_helper.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_probe_helper.h> diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c index 0cd527f0c146..794a87d16f88 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c @@ -10,10 +10,10 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> @@ -84,7 +84,7 @@ static void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane, struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); struct drm_framebuffer *fb = plane->state->fb; - struct drm_gem_cma_object *gem; + struct drm_gem_dma_object *gem; unsigned int alpha = DCU_LAYER_AB_NONE, bpp; int index; @@ -95,7 +95,7 @@ static void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane, if (index < 0) return; - gem = drm_fb_cma_get_gem_obj(fb, 0); + gem = drm_fb_dma_get_gem_obj(fb, 0); switch (fb->format->format) { case DRM_FORMAT_RGB565: @@ -136,7 +136,7 @@ static void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane, DCU_LAYER_POSY(new_state->crtc_y) | DCU_LAYER_POSX(new_state->crtc_x)); regmap_write(fsl_dev->regmap, - DCU_CTRLDESCLN(index, 3), gem->paddr); + DCU_CTRLDESCLN(index, 3), gem->dma_addr); regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4), DCU_LAYER_EN | DCU_LAYER_TRANS(0xff) | @@ -171,16 +171,10 @@ static const struct drm_plane_helper_funcs fsl_dcu_drm_plane_helper_funcs = { .atomic_update = fsl_dcu_drm_plane_atomic_update, }; -static void fsl_dcu_drm_plane_destroy(struct drm_plane *plane) -{ - drm_plane_cleanup(plane); - kfree(plane); -} - static const struct drm_plane_funcs fsl_dcu_drm_plane_funcs = { .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, - .destroy = fsl_dcu_drm_plane_destroy, + .destroy = drm_plane_helper_destroy, .disable_plane = drm_atomic_helper_disable_plane, .reset = drm_atomic_helper_plane_reset, .update_plane = drm_atomic_helper_update_plane, diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c index 9a5ea06a1a8e..531c1781a8fb 100644 --- a/drivers/gpu/drm/gma500/psb_intel_display.c +++ b/drivers/gpu/drm/gma500/psb_intel_display.c @@ -9,8 +9,6 @@ #include <linux/delay.h> #include <linux/i2c.h> -#include <drm/drm_plane_helper.h> - #include "framebuffer.h" #include "gem.h" #include "gma_display.h" diff --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c index 4873f9799f41..7c6dc2bcd14a 100644 --- a/drivers/gpu/drm/gud/gud_pipe.c +++ b/drivers/gpu/drm/gud/gud_pipe.c @@ -59,6 +59,7 @@ static size_t gud_xrgb8888_to_r124(u8 *dst, const struct drm_format_info *format unsigned int bits_per_pixel = 8 / block_width; unsigned int x, y, width, height; u8 pix, *pix8, *block = dst; /* Assign to silence compiler warning */ + struct iosys_map dst_map, vmap; size_t len; void *buf; @@ -74,7 +75,9 @@ static size_t gud_xrgb8888_to_r124(u8 *dst, const struct drm_format_info *format if (!buf) return 0; - drm_fb_xrgb8888_to_gray8(buf, 0, src, fb, rect); + iosys_map_set_vaddr(&dst_map, buf); + iosys_map_set_vaddr(&vmap, src); + drm_fb_xrgb8888_to_gray8(&dst_map, NULL, &vmap, fb, rect); pix8 = buf; for (y = 0; y < height; y++) { @@ -105,7 +108,8 @@ static size_t gud_xrgb8888_to_color(u8 *dst, const struct drm_format_info *forma unsigned int bits_per_pixel = 8 / block_width; u8 r, g, b, pix, *block = dst; /* Assign to silence compiler warning */ unsigned int x, y, width; - u32 *pix32; + __le32 *sbuf32; + u32 pix32; size_t len; /* Start on a byte boundary */ @@ -114,8 +118,8 @@ static size_t gud_xrgb8888_to_color(u8 *dst, const struct drm_format_info *forma len = drm_format_info_min_pitch(format, 0, width) * drm_rect_height(rect); for (y = rect->y1; y < rect->y2; y++) { - pix32 = src + (y * fb->pitches[0]); - pix32 += rect->x1; + sbuf32 = src + (y * fb->pitches[0]); + sbuf32 += rect->x1; for (x = 0; x < width; x++) { unsigned int pixpos = x % block_width; /* within byte from the left */ @@ -126,9 +130,10 @@ static size_t gud_xrgb8888_to_color(u8 *dst, const struct drm_format_info *forma *block = 0; } - r = *pix32 >> 16; - g = *pix32 >> 8; - b = *pix32++; + pix32 = le32_to_cpu(*sbuf32++); + r = pix32 >> 16; + g = pix32 >> 8; + b = pix32; switch (format->format) { case GUD_DRM_FORMAT_XRGB1111: @@ -154,6 +159,7 @@ static int gud_prep_flush(struct gud_device *gdrm, struct drm_framebuffer *fb, u8 compression = gdrm->compression; struct iosys_map map[DRM_FORMAT_MAX_PLANES]; struct iosys_map map_data[DRM_FORMAT_MAX_PLANES]; + struct iosys_map dst; void *vaddr, *buf; size_t pitch, len; int ret = 0; @@ -177,6 +183,7 @@ retry: buf = gdrm->compress_buf; else buf = gdrm->bulk_buf; + iosys_map_set_vaddr(&dst, buf); /* * Imported buffers are assumed to be write-combined and thus uncached @@ -190,23 +197,24 @@ retry: goto end_cpu_access; } } else if (format->format == DRM_FORMAT_R8) { - drm_fb_xrgb8888_to_gray8(buf, 0, vaddr, fb, rect); + drm_fb_xrgb8888_to_gray8(&dst, NULL, map_data, fb, rect); } else if (format->format == DRM_FORMAT_RGB332) { - drm_fb_xrgb8888_to_rgb332(buf, 0, vaddr, fb, rect); + drm_fb_xrgb8888_to_rgb332(&dst, NULL, map_data, fb, rect); } else if (format->format == DRM_FORMAT_RGB565) { - drm_fb_xrgb8888_to_rgb565(buf, 0, vaddr, fb, rect, gud_is_big_endian()); + drm_fb_xrgb8888_to_rgb565(&dst, NULL, map_data, fb, rect, + gud_is_big_endian()); } else if (format->format == DRM_FORMAT_RGB888) { - drm_fb_xrgb8888_to_rgb888(buf, 0, vaddr, fb, rect); + drm_fb_xrgb8888_to_rgb888(&dst, NULL, map_data, fb, rect); } else { len = gud_xrgb8888_to_color(buf, format, vaddr, fb, rect); } } else if (gud_is_big_endian() && format->cpp[0] > 1) { - drm_fb_swab(buf, 0, vaddr, fb, rect, !import_attach); + drm_fb_swab(&dst, NULL, map_data, fb, rect, !import_attach); } else if (compression && !import_attach && pitch == fb->pitches[0]) { /* can compress directly from the framebuffer */ buf = vaddr + rect->y1 * pitch; } else { - drm_fb_memcpy(buf, 0, vaddr, fb, rect); + drm_fb_memcpy(&dst, NULL, map_data, fb, rect); } memset(req, 0, sizeof(*req)); diff --git a/drivers/gpu/drm/hisilicon/kirin/Kconfig b/drivers/gpu/drm/hisilicon/kirin/Kconfig index b770f7662830..c5265675bf0c 100644 --- a/drivers/gpu/drm/hisilicon/kirin/Kconfig +++ b/drivers/gpu/drm/hisilicon/kirin/Kconfig @@ -3,7 +3,7 @@ config DRM_HISI_KIRIN tristate "DRM Support for Hisilicon Kirin series SoCs Platform" depends on DRM && OF && ARM64 select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_MIPI_DSI help Choose this option if you have a hisilicon Kirin chipsets(hi6220). diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c index 61c29c2834e6..871f79a6b17e 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c @@ -24,11 +24,10 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_cma_helper.h> -#include <drm/drm_plane_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> #include <drm/drm_gem_framebuffer_helper.h> @@ -549,13 +548,13 @@ static const struct drm_crtc_funcs ade_crtc_funcs = { static void ade_rdma_set(void __iomem *base, struct drm_framebuffer *fb, u32 ch, u32 y, u32 in_h, u32 fmt) { - struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, 0); + struct drm_gem_dma_object *obj = drm_fb_dma_get_gem_obj(fb, 0); u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en; u32 stride = fb->pitches[0]; - u32 addr = (u32)obj->paddr + y * stride; + u32 addr = (u32) obj->dma_addr + y * stride; DRM_DEBUG_DRIVER("rdma%d: (y=%d, height=%d), stride=%d, paddr=0x%x\n", - ch + 1, y, in_h, stride, (u32)obj->paddr); + ch + 1, y, in_h, stride, (u32) obj->dma_addr); DRM_DEBUG_DRIVER("addr=0x%x, fb:%dx%d, pixel_format=%d(%p4cc)\n", addr, fb->width, fb->height, fmt, &fb->format->format); @@ -920,12 +919,12 @@ static const struct drm_mode_config_funcs ade_mode_config_funcs = { }; -DEFINE_DRM_GEM_CMA_FOPS(ade_fops); +DEFINE_DRM_GEM_DMA_FOPS(ade_fops); static const struct drm_driver ade_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .fops = &ade_fops, - DRM_GEM_CMA_DRIVER_OPS, + DRM_GEM_DMA_DRIVER_OPS, .name = "kirin", .desc = "Hisilicon Kirin620 SoC DRM Driver", .date = "20150718", diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c index 2af51df6dca7..73ee7f25f734 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c @@ -19,9 +19,8 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_module.h> #include <drm/drm_of.h> diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c index b8e64dd8d3a6..28e732f94bf2 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c +++ b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c @@ -21,19 +21,18 @@ #include "hyperv_drm.h" static int hyperv_blit_to_vram_rect(struct drm_framebuffer *fb, - const struct iosys_map *map, + const struct iosys_map *vmap, struct drm_rect *rect) { struct hyperv_drm_device *hv = to_hv(fb->dev); - void __iomem *dst = hv->vram; - void *vmap = map->vaddr; /* TODO: Use mapping abstraction properly */ + struct iosys_map dst = IOSYS_MAP_INIT_VADDR_IOMEM(hv->vram); int idx; if (!drm_dev_enter(&hv->dev, &idx)) return -ENODEV; - dst += drm_fb_clip_offset(fb->pitches[0], fb->format, rect); - drm_fb_memcpy_toio(dst, fb->pitches[0], vmap, fb, rect); + iosys_map_incr(&dst, drm_fb_clip_offset(fb->pitches[0], fb->format, rect)); + drm_fb_memcpy(&dst, fb->pitches, vmap, fb, rect); drm_dev_exit(idx); diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c index 592e5adfed8b..0f35f2facdfc 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.c +++ b/drivers/gpu/drm/i915/display/i9xx_plane.c @@ -7,7 +7,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_blend.h> #include <drm/drm_fourcc.h> -#include <drm/drm_plane_helper.h> #include "intel_atomic.h" #include "intel_atomic_plane.h" @@ -326,8 +325,8 @@ i9xx_plane_check(struct intel_crtc_state *crtc_state, return ret; ret = intel_atomic_plane_check_clipping(plane_state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, i9xx_plane_has_windowing(plane)); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c index 40da7910f845..b94973b5633f 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic.c +++ b/drivers/gpu/drm/i915/display/intel_atomic.c @@ -32,7 +32,6 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_fourcc.h> -#include <drm/drm_plane_helper.h> #include "i915_drv.h" #include "i915_reg.h" diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_atomic_plane.c index efe8591619e3..dd876dbbaa39 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c @@ -33,7 +33,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_fourcc.h> -#include <drm/drm_plane_helper.h> #include "gt/intel_rps.h" diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index 4442aa355f86..6792a9056f46 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -9,7 +9,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_plane.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_vblank_work.h> #include "i915_irq.h" diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c index c2797ad2d313..16ac560eab49 100644 --- a/drivers/gpu/drm/i915/display/intel_cursor.c +++ b/drivers/gpu/drm/i915/display/intel_cursor.c @@ -8,7 +8,6 @@ #include <drm/drm_atomic_uapi.h> #include <drm/drm_blend.h> #include <drm/drm_damage_helper.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_fourcc.h> #include "intel_atomic.h" @@ -144,8 +143,8 @@ static int intel_check_cursor(struct intel_crtc_state *crtc_state, } ret = intel_atomic_plane_check_clipping(plane_state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, true); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index fc5d94862ef3..bf80b57ca63a 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -41,7 +41,6 @@ #include <drm/drm_damage_helper.h> #include <drm/drm_edid.h> #include <drm/drm_fourcc.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_privacy_screen_consumer.h> #include <drm/drm_probe_helper.h> #include <drm/drm_rect.h> diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c index c92d5bb2326a..83af95bce98d 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c @@ -278,6 +278,8 @@ intel_dp_aux_hdr_setup_backlight(struct intel_connector *connector, enum pipe pi { struct drm_i915_private *i915 = to_i915(connector->base.dev); struct intel_panel *panel = &connector->panel; + struct drm_luminance_range_info *luminance_range = + &connector->base.display_info.luminance_range; int ret; if (panel->backlight.edp.intel.sdr_uses_aux) { @@ -293,8 +295,17 @@ intel_dp_aux_hdr_setup_backlight(struct intel_connector *connector, enum pipe pi } } - panel->backlight.max = 512; - panel->backlight.min = 0; + if (luminance_range->max_luminance) { + panel->backlight.max = luminance_range->max_luminance; + panel->backlight.min = luminance_range->min_luminance; + } else { + panel->backlight.max = 512; + panel->backlight.min = 0; + } + + drm_dbg_kms(&i915->drm, "Using backlight range %d..%d\n", panel->backlight.min, + panel->backlight.max); + panel->backlight.level = intel_dp_aux_hdr_get_backlight(connector, pipe); panel->backlight.enabled = panel->backlight.level != 0; diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c index 2713faad0625..7649c50b5445 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.c +++ b/drivers/gpu/drm/i915/display/intel_sprite.c @@ -39,7 +39,6 @@ #include <drm/drm_crtc.h> #include <drm/drm_damage_helper.h> #include <drm/drm_fourcc.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_rect.h> #include "i915_drv.h" @@ -1355,8 +1354,8 @@ g4x_sprite_check(struct intel_crtc_state *crtc_state, { struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - int min_scale = DRM_PLANE_HELPER_NO_SCALING; - int max_scale = DRM_PLANE_HELPER_NO_SCALING; + int min_scale = DRM_PLANE_NO_SCALING; + int max_scale = DRM_PLANE_NO_SCALING; int ret; if (g4x_fb_scalable(plane_state->hw.fb)) { @@ -1426,8 +1425,8 @@ vlv_sprite_check(struct intel_crtc_state *crtc_state, return ret; ret = intel_atomic_plane_check_clipping(plane_state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, true); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index c11e15a93164..4d6a27757065 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -7,7 +7,6 @@ #include <drm/drm_blend.h> #include <drm/drm_damage_helper.h> #include <drm/drm_fourcc.h> -#include <drm/drm_plane_helper.h> #include "i915_drv.h" #include "intel_atomic_plane.h" @@ -1856,8 +1855,8 @@ static int skl_plane_check(struct intel_crtc_state *crtc_state, struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); struct drm_i915_private *dev_priv = to_i915(plane->base.dev); const struct drm_framebuffer *fb = plane_state->hw.fb; - int min_scale = DRM_PLANE_HELPER_NO_SCALING; - int max_scale = DRM_PLANE_HELPER_NO_SCALING; + int min_scale = DRM_PLANE_NO_SCALING; + int max_scale = DRM_PLANE_NO_SCALING; int ret; ret = skl_plane_check_fb(crtc_state, plane_state); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index f131dc065f47..5a5cf332d8a5 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -1242,9 +1242,8 @@ int __i915_gem_ttm_object_init(struct intel_memory_region *mem, * Similarly, in delayed_destroy, we can't call ttm_bo_put() * until successful initialization. */ - ret = ttm_bo_init_reserved(&i915->bdev, i915_gem_to_ttm(obj), size, - bo_type, &i915_sys_placement, - page_size >> PAGE_SHIFT, + ret = ttm_bo_init_reserved(&i915->bdev, i915_gem_to_ttm(obj), bo_type, + &i915_sys_placement, page_size >> PAGE_SHIFT, &ctx, NULL, NULL, i915_ttm_bo_destroy); if (ret) return i915_ttm_err_to_gem(ret); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 73cebc6aa650..783a6ca41a61 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -65,7 +65,7 @@ /* * Interrupt statistic for PMU. Increments the counter only if the - * interrupt originated from the the GPU so interrupts from a device which + * interrupt originated from the GPU so interrupts from a device which * shares the interrupt line are not accounted. */ static inline void pmu_irq_stats(struct drm_i915_private *i915, diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index f06babdb3a8c..ef7553b494ea 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -32,7 +32,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_blend.h> #include <drm/drm_fourcc.h> -#include <drm/drm_plane_helper.h> #include "display/intel_atomic.h" #include "display/intel_atomic_plane.h" diff --git a/drivers/gpu/drm/imx/Kconfig b/drivers/gpu/drm/imx/Kconfig index bb9738c7c825..975de4ff7313 100644 --- a/drivers/gpu/drm/imx/Kconfig +++ b/drivers/gpu/drm/imx/Kconfig @@ -3,7 +3,7 @@ config DRM_IMX tristate "DRM Support for Freescale i.MX" select DRM_KMS_HELPER select VIDEOMODE_HELPERS - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_KMS_HELPER depends on DRM && (ARCH_MXC || ARCH_MULTIPLATFORM || COMPILE_TEST) depends on IMX_IPUV3_CORE diff --git a/drivers/gpu/drm/imx/dcss/Kconfig b/drivers/gpu/drm/imx/dcss/Kconfig index 5c2b2277afbf..3ffc061d392b 100644 --- a/drivers/gpu/drm/imx/dcss/Kconfig +++ b/drivers/gpu/drm/imx/dcss/Kconfig @@ -2,7 +2,7 @@ config DRM_IMX_DCSS tristate "i.MX8MQ DCSS" select IMX_IRQSTEER select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select VIDEOMODE_HELPERS depends on DRM && ARCH_MXC && ARM64 help diff --git a/drivers/gpu/drm/imx/dcss/dcss-kms.c b/drivers/gpu/drm/imx/dcss/dcss-kms.c index 8cf3352d8858..b4f82ebca532 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-kms.c +++ b/drivers/gpu/drm/imx/dcss/dcss-kms.c @@ -8,7 +8,7 @@ #include <drm/drm_bridge_connector.h> #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_of.h> #include <drm/drm_probe_helper.h> @@ -17,7 +17,7 @@ #include "dcss-dev.h" #include "dcss-kms.h" -DEFINE_DRM_GEM_CMA_FOPS(dcss_cma_fops); +DEFINE_DRM_GEM_DMA_FOPS(dcss_cma_fops); static const struct drm_mode_config_funcs dcss_drm_mode_config_funcs = { .fb_create = drm_gem_fb_create, @@ -28,7 +28,7 @@ static const struct drm_mode_config_funcs dcss_drm_mode_config_funcs = { static const struct drm_driver dcss_kms_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, - DRM_GEM_CMA_DRIVER_OPS, + DRM_GEM_DMA_DRIVER_OPS, .fops = &dcss_cma_fops, .name = "imx-dcss", .desc = "i.MX8MQ Display Subsystem", diff --git a/drivers/gpu/drm/imx/dcss/dcss-plane.c b/drivers/gpu/drm/imx/dcss/dcss-plane.c index c29f343f33e5..ab6d32bad756 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-plane.c +++ b/drivers/gpu/drm/imx/dcss/dcss-plane.c @@ -6,10 +6,10 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_blend.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include "dcss-dev.h" #include "dcss-kms.h" @@ -147,7 +147,7 @@ static int dcss_plane_atomic_check(struct drm_plane *plane, struct dcss_dev *dcss = plane->dev->dev_private; struct drm_framebuffer *fb = new_plane_state->fb; bool is_primary_plane = plane->type == DRM_PLANE_TYPE_PRIMARY; - struct drm_gem_cma_object *cma_obj; + struct drm_gem_dma_object *dma_obj; struct drm_crtc_state *crtc_state; int hdisplay, vdisplay; int min, max; @@ -156,8 +156,8 @@ static int dcss_plane_atomic_check(struct drm_plane *plane, if (!fb || !new_plane_state->crtc) return 0; - cma_obj = drm_fb_cma_get_gem_obj(fb, 0); - WARN_ON(!cma_obj); + dma_obj = drm_fb_dma_get_gem_obj(fb, 0); + WARN_ON(!dma_obj); crtc_state = drm_atomic_get_existing_crtc_state(state, new_plane_state->crtc); @@ -218,26 +218,26 @@ static void dcss_plane_atomic_set_base(struct dcss_plane *dcss_plane) struct dcss_dev *dcss = plane->dev->dev_private; struct drm_framebuffer *fb = state->fb; const struct drm_format_info *format = fb->format; - struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0); + struct drm_gem_dma_object *dma_obj = drm_fb_dma_get_gem_obj(fb, 0); unsigned long p1_ba = 0, p2_ba = 0; if (!format->is_yuv || format->format == DRM_FORMAT_NV12 || format->format == DRM_FORMAT_NV21) - p1_ba = cma_obj->paddr + fb->offsets[0] + + p1_ba = dma_obj->dma_addr + fb->offsets[0] + fb->pitches[0] * (state->src.y1 >> 16) + format->char_per_block[0] * (state->src.x1 >> 16); else if (format->format == DRM_FORMAT_UYVY || format->format == DRM_FORMAT_VYUY || format->format == DRM_FORMAT_YUYV || format->format == DRM_FORMAT_YVYU) - p1_ba = cma_obj->paddr + fb->offsets[0] + + p1_ba = dma_obj->dma_addr + fb->offsets[0] + fb->pitches[0] * (state->src.y1 >> 16) + 2 * format->char_per_block[0] * (state->src.x1 >> 17); if (format->format == DRM_FORMAT_NV12 || format->format == DRM_FORMAT_NV21) - p2_ba = cma_obj->paddr + fb->offsets[1] + + p2_ba = dma_obj->dma_addr + fb->offsets[1] + (((fb->pitches[1] >> 1) * (state->src.y1 >> 17) + (state->src.x1 >> 17)) << 1); diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index a57812ec36b1..8dd8b0f912af 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c @@ -16,13 +16,11 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_managed.h> #include <drm/drm_of.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> @@ -34,7 +32,7 @@ static int legacyfb_depth = 16; module_param(legacyfb_depth, int, 0444); -DEFINE_DRM_GEM_CMA_FOPS(imx_drm_driver_fops); +DEFINE_DRM_GEM_DMA_FOPS(imx_drm_driver_fops); void imx_drm_connector_destroy(struct drm_connector *connector) { @@ -154,7 +152,7 @@ static int imx_drm_dumb_create(struct drm_file *file_priv, args->width = ALIGN(width, 8); - ret = drm_gem_cma_dumb_create(file_priv, drm, args); + ret = drm_gem_dma_dumb_create(file_priv, drm, args); if (ret) return ret; @@ -164,7 +162,7 @@ static int imx_drm_dumb_create(struct drm_file *file_priv, static const struct drm_driver imx_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, - DRM_GEM_CMA_DRIVER_OPS_WITH_DUMB_CREATE(imx_drm_dumb_create), + DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(imx_drm_dumb_create), .ioctls = imx_drm_ioctls, .num_ioctls = ARRAY_SIZE(imx_drm_ioctls), .fops = &imx_drm_driver_fops, diff --git a/drivers/gpu/drm/imx/imx-drm.h b/drivers/gpu/drm/imx/imx-drm.h index c3e1a3f14d30..e721bebda2bd 100644 --- a/drivers/gpu/drm/imx/imx-drm.h +++ b/drivers/gpu/drm/imx/imx-drm.h @@ -32,7 +32,7 @@ extern struct platform_driver ipu_drm_driver; void imx_drm_mode_config_init(struct drm_device *drm); -struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb); +struct drm_gem_dma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb); int imx_drm_encoder_parse_of(struct drm_device *drm, struct drm_encoder *encoder, struct device_node *np); diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index f7863d6dea80..5f26090b0c98 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c @@ -18,8 +18,7 @@ #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> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_managed.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index ea5f594955df..dba4f7d81d69 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c @@ -8,13 +8,12 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_blend.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_managed.h> -#include <drm/drm_plane_helper.h> #include <video/imx-ipu-v3.h> @@ -126,14 +125,14 @@ static inline unsigned long drm_plane_state_to_eba(struct drm_plane_state *state, int plane) { struct drm_framebuffer *fb = state->fb; - struct drm_gem_cma_object *cma_obj; + struct drm_gem_dma_object *dma_obj; int x = state->src.x1 >> 16; int y = state->src.y1 >> 16; - cma_obj = drm_fb_cma_get_gem_obj(fb, plane); - BUG_ON(!cma_obj); + dma_obj = drm_fb_dma_get_gem_obj(fb, plane); + BUG_ON(!dma_obj); - return cma_obj->paddr + fb->offsets[plane] + fb->pitches[plane] * y + + return dma_obj->dma_addr + fb->offsets[plane] + fb->pitches[plane] * y + fb->format->cpp[plane] * x; } @@ -141,18 +140,18 @@ static inline unsigned long drm_plane_state_to_ubo(struct drm_plane_state *state) { struct drm_framebuffer *fb = state->fb; - struct drm_gem_cma_object *cma_obj; + struct drm_gem_dma_object *dma_obj; unsigned long eba = drm_plane_state_to_eba(state, 0); int x = state->src.x1 >> 16; int y = state->src.y1 >> 16; - cma_obj = drm_fb_cma_get_gem_obj(fb, 1); - BUG_ON(!cma_obj); + dma_obj = drm_fb_dma_get_gem_obj(fb, 1); + BUG_ON(!dma_obj); x /= fb->format->hsub; y /= fb->format->vsub; - return cma_obj->paddr + fb->offsets[1] + fb->pitches[1] * y + + return dma_obj->dma_addr + fb->offsets[1] + fb->pitches[1] * y + fb->format->cpp[1] * x - eba; } @@ -160,18 +159,18 @@ static inline unsigned long drm_plane_state_to_vbo(struct drm_plane_state *state) { struct drm_framebuffer *fb = state->fb; - struct drm_gem_cma_object *cma_obj; + struct drm_gem_dma_object *dma_obj; unsigned long eba = drm_plane_state_to_eba(state, 0); int x = state->src.x1 >> 16; int y = state->src.y1 >> 16; - cma_obj = drm_fb_cma_get_gem_obj(fb, 2); - BUG_ON(!cma_obj); + dma_obj = drm_fb_dma_get_gem_obj(fb, 2); + BUG_ON(!dma_obj); x /= fb->format->hsub; y /= fb->format->vsub; - return cma_obj->paddr + fb->offsets[2] + fb->pitches[2] * y + + return dma_obj->dma_addr + fb->offsets[2] + fb->pitches[2] * y + fb->format->cpp[2] * x - eba; } @@ -393,8 +392,8 @@ static int ipu_plane_atomic_check(struct drm_plane *plane, return -EINVAL; ret = drm_atomic_helper_check_plane_state(new_state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, can_position, true); if (ret) return ret; diff --git a/drivers/gpu/drm/ingenic/Kconfig b/drivers/gpu/drm/ingenic/Kconfig index 090830bcbde7..a53f475d33df 100644 --- a/drivers/gpu/drm/ingenic/Kconfig +++ b/drivers/gpu/drm/ingenic/Kconfig @@ -8,7 +8,7 @@ config DRM_INGENIC select DRM_BRIDGE select DRM_PANEL_BRIDGE select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE help Choose this option for DRM support for the Ingenic SoCs. diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c index eb8208bfe5ab..ab0515d2c420 100644 --- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c +++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c @@ -30,8 +30,8 @@ #include <drm/drm_damage_helper.h> #include <drm/drm_drv.h> #include <drm/drm_encoder.h> -#include <drm/drm_gem_cma_helper.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> @@ -41,7 +41,6 @@ #include <drm/drm_of.h> #include <drm/drm_panel.h> #include <drm/drm_plane.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> @@ -482,8 +481,8 @@ static int ingenic_drm_plane_atomic_check(struct drm_plane *plane, return PTR_ERR(priv_state); ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, priv->soc_info->has_osd, true); if (ret) @@ -670,12 +669,12 @@ static void ingenic_drm_plane_atomic_update(struct drm_plane *plane, if (newstate && newstate->fb) { if (priv->soc_info->map_noncoherent) - drm_fb_cma_sync_non_coherent(&priv->drm, oldstate, newstate); + drm_fb_dma_sync_non_coherent(&priv->drm, oldstate, newstate); crtc_state = newstate->crtc->state; plane_id = !!(priv->soc_info->has_osd && plane != &priv->f0); - addr = drm_fb_cma_get_gem_addr(newstate->fb, newstate, 0); + addr = drm_fb_dma_get_gem_addr(newstate->fb, newstate, 0); width = newstate->src_w >> 16; height = newstate->src_h >> 16; cpp = newstate->fb->format->cpp[0]; @@ -915,7 +914,7 @@ static struct drm_gem_object * ingenic_drm_gem_create_object(struct drm_device *drm, size_t size) { struct ingenic_drm *priv = drm_device_get_priv(drm); - struct drm_gem_cma_object *obj; + struct drm_gem_dma_object *obj; obj = kzalloc(sizeof(*obj), GFP_KERNEL); if (!obj) @@ -948,7 +947,7 @@ static void ingenic_drm_destroy_state(struct drm_private_obj *obj, kfree(priv_state); } -DEFINE_DRM_GEM_CMA_FOPS(ingenic_drm_fops); +DEFINE_DRM_GEM_DMA_FOPS(ingenic_drm_fops); static const struct drm_driver ingenic_drm_driver_data = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, @@ -961,7 +960,7 @@ static const struct drm_driver ingenic_drm_driver_data = { .fops = &ingenic_drm_fops, .gem_create_object = ingenic_drm_gem_create_object, - DRM_GEM_CMA_DRIVER_OPS, + DRM_GEM_DMA_DRIVER_OPS, }; static const struct drm_plane_funcs ingenic_drm_primary_plane_funcs = { @@ -1464,21 +1463,22 @@ static int ingenic_drm_remove(struct platform_device *pdev) return 0; } -static int __maybe_unused ingenic_drm_suspend(struct device *dev) +static int ingenic_drm_suspend(struct device *dev) { struct ingenic_drm *priv = dev_get_drvdata(dev); return drm_mode_config_helper_suspend(&priv->drm); } -static int __maybe_unused ingenic_drm_resume(struct device *dev) +static int ingenic_drm_resume(struct device *dev) { struct ingenic_drm *priv = dev_get_drvdata(dev); return drm_mode_config_helper_resume(&priv->drm); } -static SIMPLE_DEV_PM_OPS(ingenic_drm_pm_ops, ingenic_drm_suspend, ingenic_drm_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(ingenic_drm_pm_ops, + ingenic_drm_suspend, ingenic_drm_resume); static const u32 jz4740_formats[] = { DRM_FORMAT_XRGB1555, @@ -1541,6 +1541,32 @@ static const struct jz_soc_info jz4725b_soc_info = { .num_formats_f0 = ARRAY_SIZE(jz4725b_formats_f0), }; +static const struct jz_soc_info jz4760_soc_info = { + .needs_dev_clk = false, + .has_osd = true, + .map_noncoherent = false, + .max_width = 1280, + .max_height = 720, + .max_burst = JZ_LCD_CTRL_BURST_32, + .formats_f1 = jz4770_formats_f1, + .num_formats_f1 = ARRAY_SIZE(jz4770_formats_f1), + .formats_f0 = jz4770_formats_f0, + .num_formats_f0 = ARRAY_SIZE(jz4770_formats_f0), +}; + +static const struct jz_soc_info jz4760b_soc_info = { + .needs_dev_clk = false, + .has_osd = true, + .map_noncoherent = false, + .max_width = 1280, + .max_height = 720, + .max_burst = JZ_LCD_CTRL_BURST_64, + .formats_f1 = jz4770_formats_f1, + .num_formats_f1 = ARRAY_SIZE(jz4770_formats_f1), + .formats_f0 = jz4770_formats_f0, + .num_formats_f0 = ARRAY_SIZE(jz4770_formats_f0), +}; + static const struct jz_soc_info jz4770_soc_info = { .needs_dev_clk = false, .has_osd = true, @@ -1572,6 +1598,8 @@ static const struct jz_soc_info jz4780_soc_info = { static const struct of_device_id ingenic_drm_of_match[] = { { .compatible = "ingenic,jz4740-lcd", .data = &jz4740_soc_info }, { .compatible = "ingenic,jz4725b-lcd", .data = &jz4725b_soc_info }, + { .compatible = "ingenic,jz4760-lcd", .data = &jz4760_soc_info }, + { .compatible = "ingenic,jz4760b-lcd", .data = &jz4760b_soc_info }, { .compatible = "ingenic,jz4770-lcd", .data = &jz4770_soc_info }, { .compatible = "ingenic,jz4780-lcd", .data = &jz4780_soc_info }, { /* sentinel */ }, @@ -1581,7 +1609,7 @@ MODULE_DEVICE_TABLE(of, ingenic_drm_of_match); static struct platform_driver ingenic_drm_driver = { .driver = { .name = "ingenic-drm", - .pm = pm_ptr(&ingenic_drm_pm_ops), + .pm = pm_sleep_ptr(&ingenic_drm_pm_ops), .of_match_table = of_match_ptr(ingenic_drm_of_match), }, .probe = ingenic_drm_probe, @@ -1616,4 +1644,4 @@ module_exit(ingenic_drm_exit); MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>"); MODULE_DESCRIPTION("DRM driver for the Ingenic SoCs\n"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/ingenic/ingenic-ipu.c b/drivers/gpu/drm/ingenic/ingenic-ipu.c index 32a50935aa6d..7a43505011a5 100644 --- a/drivers/gpu/drm/ingenic/ingenic-ipu.c +++ b/drivers/gpu/drm/ingenic/ingenic-ipu.c @@ -22,14 +22,13 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_damage_helper.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_plane.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_property.h> #include <drm/drm_vblank.h> @@ -363,15 +362,15 @@ static void ingenic_ipu_plane_atomic_update(struct drm_plane *plane, } if (ingenic_drm_map_noncoherent(ipu->master)) - drm_fb_cma_sync_non_coherent(ipu->drm, oldstate, newstate); + drm_fb_dma_sync_non_coherent(ipu->drm, oldstate, newstate); /* New addresses will be committed in vblank handler... */ - ipu->addr_y = drm_fb_cma_get_gem_addr(newstate->fb, newstate, 0); + ipu->addr_y = drm_fb_dma_get_gem_addr(newstate->fb, newstate, 0); if (finfo->num_planes > 1) - ipu->addr_u = drm_fb_cma_get_gem_addr(newstate->fb, newstate, + ipu->addr_u = drm_fb_dma_get_gem_addr(newstate->fb, newstate, 1); if (finfo->num_planes > 2) - ipu->addr_v = drm_fb_cma_get_gem_addr(newstate->fb, newstate, + ipu->addr_v = drm_fb_dma_get_gem_addr(newstate->fb, newstate, 2); if (!needs_modeset) @@ -697,10 +696,12 @@ ingenic_ipu_plane_atomic_set_property(struct drm_plane *plane, { struct ingenic_ipu *ipu = plane_to_ingenic_ipu(plane); struct drm_crtc_state *crtc_state; + bool mode_changed; if (property != ipu->sharpness_prop) return -EINVAL; + mode_changed = val != ipu->sharpness; ipu->sharpness = val; if (state->crtc) { @@ -708,7 +709,7 @@ ingenic_ipu_plane_atomic_set_property(struct drm_plane *plane, if (WARN_ON(!crtc_state)) return -EINVAL; - crtc_state->mode_changed = true; + crtc_state->mode_changed |= mode_changed; } return 0; diff --git a/drivers/gpu/drm/kmb/Kconfig b/drivers/gpu/drm/kmb/Kconfig index 5fdd43dad507..fd011367db1d 100644 --- a/drivers/gpu/drm/kmb/Kconfig +++ b/drivers/gpu/drm/kmb/Kconfig @@ -3,7 +3,7 @@ config DRM_KMB_DISPLAY depends on DRM depends on ARCH_KEEMBAY || COMPILE_TEST select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_MIPI_DSI help Choose this option if you have Intel's KeemBay SOC which integrates diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 76fef0880504..2382ccb3ee99 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -16,7 +16,7 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_module.h> #include <drm/drm_probe_helper.h> @@ -433,14 +433,14 @@ static void kmb_irq_uninstall(struct drm_device *drm) free_irq(kmb->irq_lcd, drm); } -DEFINE_DRM_GEM_CMA_FOPS(fops); +DEFINE_DRM_GEM_DMA_FOPS(fops); static const struct drm_driver kmb_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, /* GEM Operations */ .fops = &fops, - DRM_GEM_CMA_DRIVER_OPS_VMAP, + DRM_GEM_DMA_DRIVER_OPS_VMAP, .name = "kmb-drm", .desc = "KEEMBAY DISPLAY DRIVER", .date = DRIVER_DATE, diff --git a/drivers/gpu/drm/kmb/kmb_plane.c b/drivers/gpu/drm/kmb/kmb_plane.c index 89d055a089a6..a42f63f6f957 100644 --- a/drivers/gpu/drm/kmb/kmb_plane.c +++ b/drivers/gpu/drm/kmb/kmb_plane.c @@ -8,13 +8,12 @@ #include <drm/drm_blend.h> #include <drm/drm_crtc.h> #include <drm/drm_crtc_helper.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_managed.h> -#include <drm/drm_plane_helper.h> #include "kmb_drv.h" #include "kmb_plane.h" @@ -136,8 +135,8 @@ static int kmb_plane_atomic_check(struct drm_plane *plane, new_plane_state->crtc); return drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, can_position, true); } @@ -404,7 +403,7 @@ static void kmb_plane_atomic_update(struct drm_plane *plane, kmb_write_lcd(kmb, LCD_LAYERn_DMA_LINE_WIDTH(plane_id), (width * fb->format->cpp[0])); - addr[Y_PLANE] = drm_fb_cma_get_gem_addr(fb, new_plane_state, 0); + addr[Y_PLANE] = drm_fb_dma_get_gem_addr(fb, new_plane_state, 0); kmb_write_lcd(kmb, LCD_LAYERn_DMA_START_ADDR(plane_id), addr[Y_PLANE] + fb->offsets[0]); val = get_pixel_format(fb->format->format); @@ -416,7 +415,7 @@ static void kmb_plane_atomic_update(struct drm_plane *plane, kmb_write_lcd(kmb, LCD_LAYERn_DMA_CB_LINE_WIDTH(plane_id), (width * fb->format->cpp[0])); - addr[U_PLANE] = drm_fb_cma_get_gem_addr(fb, new_plane_state, + addr[U_PLANE] = drm_fb_dma_get_gem_addr(fb, new_plane_state, U_PLANE); /* check if Cb/Cr is swapped*/ if (num_planes == 3 && (val & LCD_LAYER_CRCB_ORDER)) @@ -437,7 +436,7 @@ static void kmb_plane_atomic_update(struct drm_plane *plane, LCD_LAYERn_DMA_CR_LINE_WIDTH(plane_id), ((width) * fb->format->cpp[0])); - addr[V_PLANE] = drm_fb_cma_get_gem_addr(fb, + addr[V_PLANE] = drm_fb_dma_get_gem_addr(fb, new_plane_state, V_PLANE); diff --git a/drivers/gpu/drm/logicvc/Kconfig b/drivers/gpu/drm/logicvc/Kconfig index 300b2be07385..fa7a88368809 100644 --- a/drivers/gpu/drm/logicvc/Kconfig +++ b/drivers/gpu/drm/logicvc/Kconfig @@ -3,7 +3,7 @@ config DRM_LOGICVC depends on DRM depends on OF || COMPILE_TEST select DRM_KMS_HELPER - select DRM_KMS_CMA_HELPER - select DRM_GEM_CMA_HELPER + select DRM_KMS_DMA_HELPER + select DRM_GEM_DMA_HELPER help DRM display driver for the logiCVC programmable logic block from Xylon diff --git a/drivers/gpu/drm/logicvc/logicvc_crtc.c b/drivers/gpu/drm/logicvc/logicvc_crtc.c index c94bb9bb456b..43a675d03808 100644 --- a/drivers/gpu/drm/logicvc/logicvc_crtc.c +++ b/drivers/gpu/drm/logicvc/logicvc_crtc.c @@ -12,7 +12,7 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_drv.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_print.h> #include <drm/drm_vblank.h> diff --git a/drivers/gpu/drm/logicvc/logicvc_drm.c b/drivers/gpu/drm/logicvc/logicvc_drm.c index 65a050176c33..cc9a4e965f77 100644 --- a/drivers/gpu/drm/logicvc/logicvc_drm.c +++ b/drivers/gpu/drm/logicvc/logicvc_drm.c @@ -18,7 +18,7 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_print.h> #include "logicvc_crtc.h" @@ -29,9 +29,9 @@ #include "logicvc_of.h" #include "logicvc_regs.h" -DEFINE_DRM_GEM_CMA_FOPS(logicvc_drm_fops); +DEFINE_DRM_GEM_DMA_FOPS(logicvc_drm_fops); -static int logicvc_drm_gem_cma_dumb_create(struct drm_file *file_priv, +static int logicvc_drm_gem_dma_dumb_create(struct drm_file *file_priv, struct drm_device *drm_dev, struct drm_mode_create_dumb *args) { @@ -40,7 +40,7 @@ static int logicvc_drm_gem_cma_dumb_create(struct drm_file *file_priv, /* Stride is always fixed to its configuration value. */ args->pitch = logicvc->config.row_stride * DIV_ROUND_UP(args->bpp, 8); - return drm_gem_cma_dumb_create_internal(file_priv, drm_dev, args); + return drm_gem_dma_dumb_create_internal(file_priv, drm_dev, args); } static struct drm_driver logicvc_drm_driver = { @@ -54,7 +54,7 @@ static struct drm_driver logicvc_drm_driver = { .major = 1, .minor = 0, - DRM_GEM_CMA_DRIVER_OPS_VMAP_WITH_DUMB_CREATE(logicvc_drm_gem_cma_dumb_create), + DRM_GEM_DMA_DRIVER_OPS_VMAP_WITH_DUMB_CREATE(logicvc_drm_gem_dma_dumb_create), }; static struct regmap_config logicvc_drm_regmap_config = { diff --git a/drivers/gpu/drm/logicvc/logicvc_interface.c b/drivers/gpu/drm/logicvc/logicvc_interface.c index c73592f6c406..815cebb4c4ca 100644 --- a/drivers/gpu/drm/logicvc/logicvc_interface.c +++ b/drivers/gpu/drm/logicvc/logicvc_interface.c @@ -12,7 +12,7 @@ #include <drm/drm_crtc_helper.h> #include <drm/drm_drv.h> #include <drm/drm_encoder.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_of.h> #include <drm/drm_panel.h> diff --git a/drivers/gpu/drm/logicvc/logicvc_layer.c b/drivers/gpu/drm/logicvc/logicvc_layer.c index 441e3cfce4cf..464000aea765 100644 --- a/drivers/gpu/drm/logicvc/logicvc_layer.c +++ b/drivers/gpu/drm/logicvc/logicvc_layer.c @@ -10,11 +10,10 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_blend.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_plane.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_print.h> #include "logicvc_crtc.h" @@ -117,8 +116,8 @@ static int logicvc_plane_atomic_check(struct drm_plane *drm_plane, } } - min_scale = DRM_PLANE_HELPER_NO_SCALING; - max_scale = DRM_PLANE_HELPER_NO_SCALING; + min_scale = DRM_PLANE_NO_SCALING; + max_scale = DRM_PLANE_NO_SCALING; can_position = (drm_plane->type == DRM_PLANE_TYPE_OVERLAY && layer->index != (logicvc->config.layers_count - 1) && @@ -158,7 +157,7 @@ static void logicvc_plane_atomic_update(struct drm_plane *drm_plane, new_state->crtc_h - 1); if (logicvc->caps->layer_address) { - phys_addr_t fb_addr = drm_fb_cma_get_gem_addr(fb, new_state, 0); + phys_addr_t fb_addr = drm_fb_dma_get_gem_addr(fb, new_state, 0); regmap_write(logicvc->regmap, LOGICVC_LAYER_ADDRESS_REG(index), fb_addr); @@ -281,7 +280,7 @@ int logicvc_layer_buffer_find_setup(struct logicvc_drm *logicvc, return -ENOMEM; } - fb_addr = drm_fb_cma_get_gem_addr(fb, state, 0); + fb_addr = drm_fb_dma_get_gem_addr(fb, state, 0); if (fb_addr < logicvc->reserved_mem_base) { drm_err(drm_dev, "Framebuffer memory below reserved memory base!\n"); diff --git a/drivers/gpu/drm/logicvc/logicvc_mode.c b/drivers/gpu/drm/logicvc/logicvc_mode.c index 11940704f644..d8207ffda1af 100644 --- a/drivers/gpu/drm/logicvc/logicvc_mode.c +++ b/drivers/gpu/drm/logicvc/logicvc_mode.c @@ -10,9 +10,8 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_mode_config.h> #include <drm/drm_panel.h> diff --git a/drivers/gpu/drm/mcde/Kconfig b/drivers/gpu/drm/mcde/Kconfig index d0bf1bc8da3f..4f3d68e11bc1 100644 --- a/drivers/gpu/drm/mcde/Kconfig +++ b/drivers/gpu/drm/mcde/Kconfig @@ -10,7 +10,7 @@ config DRM_MCDE select DRM_BRIDGE select DRM_PANEL_BRIDGE select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE help Choose this option for DRM support for the ST-Ericsson MCDE diff --git a/drivers/gpu/drm/mcde/mcde_display.c b/drivers/gpu/drm/mcde/mcde_display.c index 4df477540d07..52043a12a2e8 100644 --- a/drivers/gpu/drm/mcde/mcde_display.c +++ b/drivers/gpu/drm/mcde/mcde_display.c @@ -11,11 +11,11 @@ #include <linux/media-bus-format.h> #include <drm/drm_device.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_mipi_dsi.h> #include <drm/drm_simple_kms_helper.h> #include <drm/drm_bridge.h> @@ -165,7 +165,7 @@ static int mcde_display_check(struct drm_simple_display_pipe *pipe, struct drm_framebuffer *fb = pstate->fb; if (fb) { - u32 offset = drm_fb_cma_get_gem_addr(fb, pstate, 0); + u32 offset = drm_fb_dma_get_gem_addr(fb, pstate, 0); /* FB base address must be dword aligned. */ if (offset & 3) { @@ -1424,7 +1424,7 @@ static void mcde_display_update(struct drm_simple_display_pipe *pipe, * from the DRM core before the display is enabled. */ if (fb) { - mcde_set_extsrc(mcde, drm_fb_cma_get_gem_addr(fb, pstate, 0)); + mcde_set_extsrc(mcde, drm_fb_dma_get_gem_addr(fb, pstate, 0)); dev_info_once(mcde->dev, "first update of display contents\n"); /* * Usually the flow is already active, unless we are in diff --git a/drivers/gpu/drm/mcde/mcde_drv.c b/drivers/gpu/drm/mcde/mcde_drv.c index e601baa87e55..1c4482ad507d 100644 --- a/drivers/gpu/drm/mcde/mcde_drv.c +++ b/drivers/gpu/drm/mcde/mcde_drv.c @@ -37,7 +37,7 @@ * (effectively using channels 0..3) for concurrent use. * * In the current DRM/KMS setup, we use one external source, one overlay, - * one FIFO and one formatter which we connect to the simple CMA framebuffer + * one FIFO and one formatter which we connect to the simple DMA framebuffer * helpers. We then provide a bridge to the DSI port, and on the DSI port * bridge we connect hang a panel bridge or other bridge. This may be subject * to change as we exploit more of the hardware capabilities. @@ -68,10 +68,10 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_gem.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_managed.h> #include <drm/drm_of.h> @@ -198,7 +198,7 @@ static int mcde_modeset_init(struct drm_device *drm) return 0; } -DEFINE_DRM_GEM_CMA_FOPS(drm_fops); +DEFINE_DRM_GEM_DMA_FOPS(drm_fops); static const struct drm_driver mcde_drm_driver = { .driver_features = @@ -212,7 +212,7 @@ static const struct drm_driver mcde_drm_driver = { .major = 1, .minor = 0, .patchlevel = 0, - DRM_GEM_CMA_DRIVER_OPS, + DRM_GEM_DMA_DRIVER_OPS, }; static int mcde_drm_bind(struct device *dev) diff --git a/drivers/gpu/drm/mediatek/Kconfig b/drivers/gpu/drm/mediatek/Kconfig index 2976d21e9a34..6d7d0e207082 100644 --- a/drivers/gpu/drm/mediatek/Kconfig +++ b/drivers/gpu/drm/mediatek/Kconfig @@ -7,7 +7,7 @@ config DRM_MEDIATEK depends on HAVE_ARM_SMCCC depends on OF depends on MTK_MMSYS - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_KMS_HELPER select DRM_MIPI_DSI select DRM_PANEL diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c index 42cc7052b050..112615817dcb 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c @@ -15,7 +15,6 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index 0e4c77724b05..5f02f8d0e4fc 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -20,7 +20,7 @@ #include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_gem.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_of.h> #include <drm/drm_probe_helper.h> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.c b/drivers/gpu/drm/mediatek/mtk_drm_gem.c index 139d7724c6d0..47e96b0289f9 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_gem.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_gem.c @@ -8,7 +8,7 @@ #include <drm/drm.h> #include <drm/drm_device.h> #include <drm/drm_gem.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_prime.h> #include "mtk_drm_drv.h" @@ -22,7 +22,7 @@ static const struct drm_gem_object_funcs mtk_drm_gem_object_funcs = { .vmap = mtk_drm_gem_prime_vmap, .vunmap = mtk_drm_gem_prime_vunmap, .mmap = mtk_drm_gem_object_mmap, - .vm_ops = &drm_gem_cma_vm_ops, + .vm_ops = &drm_gem_dma_vm_ops, }; static struct mtk_drm_gem_obj *mtk_drm_gem_init(struct drm_device *dev, diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c index 5c0d9ce69931..2f5e007dd380 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c @@ -11,7 +11,6 @@ #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_plane_helper.h> #include "mtk_drm_crtc.h" #include "mtk_drm_ddp_comp.h" @@ -108,8 +107,8 @@ static int mtk_plane_atomic_async_check(struct drm_plane *plane, crtc_state = new_plane_state->crtc->state; return drm_atomic_helper_check_plane_state(plane->state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, true, true); } @@ -202,8 +201,8 @@ static int mtk_plane_atomic_check(struct drm_plane *plane, return drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, true, true); } diff --git a/drivers/gpu/drm/meson/Kconfig b/drivers/gpu/drm/meson/Kconfig index 6c70fc3214af..823909da87db 100644 --- a/drivers/gpu/drm/meson/Kconfig +++ b/drivers/gpu/drm/meson/Kconfig @@ -4,7 +4,7 @@ config DRM_MESON depends on DRM && OF && (ARM || ARM64) depends on ARCH_MESON || COMPILE_TEST select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_DISPLAY_CONNECTOR select VIDEOMODE_HELPERS select REGMAP_MMIO diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index bd4ca11d3ff5..fcf0d493782c 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -19,7 +19,7 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_module.h> @@ -87,16 +87,16 @@ static int meson_dumb_create(struct drm_file *file, struct drm_device *dev, args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8), SZ_64); args->size = PAGE_ALIGN(args->pitch * args->height); - return drm_gem_cma_dumb_create_internal(file, dev, args); + return drm_gem_dma_dumb_create_internal(file, dev, args); } -DEFINE_DRM_GEM_CMA_FOPS(fops); +DEFINE_DRM_GEM_DMA_FOPS(fops); static const struct drm_driver meson_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, - /* CMA Ops */ - DRM_GEM_CMA_DRIVER_OPS_WITH_DUMB_CREATE(meson_dumb_create), + /* DMA Ops */ + DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(meson_dumb_create), /* Misc */ .fops = &fops, diff --git a/drivers/gpu/drm/meson/meson_overlay.c b/drivers/gpu/drm/meson/meson_overlay.c index b4a0518c1028..7f98de38842b 100644 --- a/drivers/gpu/drm/meson/meson_overlay.c +++ b/drivers/gpu/drm/meson/meson_overlay.c @@ -11,12 +11,11 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_blend.h> #include <drm/drm_device.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> -#include <drm/drm_plane_helper.h> +#include <drm/drm_gem_dma_helper.h> #include "meson_overlay.h" #include "meson_registers.h" @@ -477,7 +476,7 @@ static void meson_overlay_atomic_update(struct drm_plane *plane, plane); struct drm_framebuffer *fb = new_state->fb; struct meson_drm *priv = meson_overlay->priv; - struct drm_gem_cma_object *gem; + struct drm_gem_dma_object *gem; unsigned long flags; bool interlace_mode; @@ -651,8 +650,8 @@ static void meson_overlay_atomic_update(struct drm_plane *plane, switch (priv->viu.vd1_planes) { case 3: - gem = drm_fb_cma_get_gem_obj(fb, 2); - priv->viu.vd1_addr2 = gem->paddr + fb->offsets[2]; + gem = drm_fb_dma_get_gem_obj(fb, 2); + priv->viu.vd1_addr2 = gem->dma_addr + fb->offsets[2]; priv->viu.vd1_stride2 = fb->pitches[2]; priv->viu.vd1_height2 = drm_format_info_plane_height(fb->format, @@ -663,8 +662,8 @@ static void meson_overlay_atomic_update(struct drm_plane *plane, priv->viu.vd1_height2); fallthrough; case 2: - gem = drm_fb_cma_get_gem_obj(fb, 1); - priv->viu.vd1_addr1 = gem->paddr + fb->offsets[1]; + gem = drm_fb_dma_get_gem_obj(fb, 1); + priv->viu.vd1_addr1 = gem->dma_addr + fb->offsets[1]; priv->viu.vd1_stride1 = fb->pitches[1]; priv->viu.vd1_height1 = drm_format_info_plane_height(fb->format, @@ -675,8 +674,8 @@ static void meson_overlay_atomic_update(struct drm_plane *plane, priv->viu.vd1_height1); fallthrough; case 1: - gem = drm_fb_cma_get_gem_obj(fb, 0); - priv->viu.vd1_addr0 = gem->paddr + fb->offsets[0]; + gem = drm_fb_dma_get_gem_obj(fb, 0); + priv->viu.vd1_addr0 = gem->dma_addr + fb->offsets[0]; priv->viu.vd1_stride0 = fb->pitches[0]; priv->viu.vd1_height0 = drm_format_info_plane_height(fb->format, diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c index b9ac932af8d0..dfd6a9f33dda 100644 --- a/drivers/gpu/drm/meson/meson_plane.c +++ b/drivers/gpu/drm/meson/meson_plane.c @@ -15,12 +15,11 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_blend.h> #include <drm/drm_device.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> -#include <drm/drm_plane_helper.h> +#include <drm/drm_gem_dma_helper.h> #include "meson_plane.h" #include "meson_registers.h" @@ -95,7 +94,7 @@ static int meson_plane_atomic_check(struct drm_plane *plane, return drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, FRAC_16_16(1, 5), - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, false, true); } @@ -140,7 +139,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane, struct drm_rect dest = drm_plane_state_dest(new_state); struct meson_drm *priv = meson_plane->priv; struct drm_framebuffer *fb = new_state->fb; - struct drm_gem_cma_object *gem; + struct drm_gem_dma_object *gem; unsigned long flags; int vsc_ini_rcv_num, vsc_ini_rpt_p0_num; int vsc_bot_rcv_num, vsc_bot_rpt_p0_num; @@ -366,9 +365,9 @@ static void meson_plane_atomic_update(struct drm_plane *plane, } /* Update Canvas with buffer address */ - gem = drm_fb_cma_get_gem_obj(fb, 0); + gem = drm_fb_dma_get_gem_obj(fb, 0); - priv->viu.osd1_addr = gem->paddr; + priv->viu.osd1_addr = gem->dma_addr; priv->viu.osd1_stride = fb->pitches[0]; priv->viu.osd1_height = fb->height; priv->viu.osd1_width = fb->width; diff --git a/drivers/gpu/drm/mgag200/Makefile b/drivers/gpu/drm/mgag200/Makefile index 89558549c3af..182e224c460d 100644 --- a/drivers/gpu/drm/mgag200/Makefile +++ b/drivers/gpu/drm/mgag200/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only mgag200-y := \ + mgag200_bmc.o \ mgag200_drv.o \ mgag200_g200.o \ mgag200_g200eh.o \ @@ -10,7 +11,6 @@ mgag200-y := \ mgag200_g200se.o \ mgag200_g200wb.o \ mgag200_i2c.o \ - mgag200_mode.o \ - mgag200_pll.o + mgag200_mode.o obj-$(CONFIG_DRM_MGAG200) += mgag200.o diff --git a/drivers/gpu/drm/mgag200/mgag200_bmc.c b/drivers/gpu/drm/mgag200/mgag200_bmc.c new file mode 100644 index 000000000000..2ba2e3c5086a --- /dev/null +++ b/drivers/gpu/drm/mgag200/mgag200_bmc.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/delay.h> + +#include "mgag200_drv.h" + +void mgag200_bmc_disable_vidrst(struct mga_device *mdev) +{ + u8 tmp; + int iter_max; + + /* + * 1 - The first step is to inform the BMC of an upcoming mode + * change. We are putting the misc<0> to output. + */ + + WREG8(DAC_INDEX, MGA1064_GEN_IO_CTL); + tmp = RREG8(DAC_DATA); + tmp |= 0x10; + WREG_DAC(MGA1064_GEN_IO_CTL, tmp); + + /* we are putting a 1 on the misc<0> line */ + WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA); + tmp = RREG8(DAC_DATA); + tmp |= 0x10; + WREG_DAC(MGA1064_GEN_IO_DATA, tmp); + + /* + * 2- Second step to mask any further scan request. This is + * done by asserting the remfreqmsk bit (XSPAREREG<7>) + */ + + WREG8(DAC_INDEX, MGA1064_SPAREREG); + tmp = RREG8(DAC_DATA); + tmp |= 0x80; + WREG_DAC(MGA1064_SPAREREG, tmp); + + /* + * 3a- The third step is to verify if there is an active scan. + * We are waiting for a 0 on remhsyncsts <XSPAREREG<0>). + */ + iter_max = 300; + while (!(tmp & 0x1) && iter_max) { + WREG8(DAC_INDEX, MGA1064_SPAREREG); + tmp = RREG8(DAC_DATA); + udelay(1000); + iter_max--; + } + + /* + * 3b- This step occurs only if the remove is actually + * scanning. We are waiting for the end of the frame which is + * a 1 on remvsyncsts (XSPAREREG<1>) + */ + if (iter_max) { + iter_max = 300; + while ((tmp & 0x2) && iter_max) { + WREG8(DAC_INDEX, MGA1064_SPAREREG); + tmp = RREG8(DAC_DATA); + udelay(1000); + iter_max--; + } + } +} + +void mgag200_bmc_enable_vidrst(struct mga_device *mdev) +{ + u8 tmp; + + /* Ensure that the vrsten and hrsten are set */ + WREG8(MGAREG_CRTCEXT_INDEX, 1); + tmp = RREG8(MGAREG_CRTCEXT_DATA); + WREG8(MGAREG_CRTCEXT_DATA, tmp | 0x88); + + /* Assert rstlvl2 */ + WREG8(DAC_INDEX, MGA1064_REMHEADCTL2); + tmp = RREG8(DAC_DATA); + tmp |= 0x8; + WREG8(DAC_DATA, tmp); + + udelay(10); + + /* Deassert rstlvl2 */ + tmp &= ~0x08; + WREG8(DAC_INDEX, MGA1064_REMHEADCTL2); + WREG8(DAC_DATA, tmp); + + /* Remove mask of scan request */ + WREG8(DAC_INDEX, MGA1064_SPAREREG); + tmp = RREG8(DAC_DATA); + tmp &= ~0x80; + WREG8(DAC_DATA, tmp); + + /* Put back a 0 on the misc<0> line */ + WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA); + tmp = RREG8(DAC_DATA); + tmp &= ~0x10; + WREG_DAC(MGA1064_GEN_IO_DATA, tmp); +} diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index 251a1bb648cc..4d38b8e18030 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -155,15 +155,16 @@ int mgag200_device_preinit(struct mga_device *mdev) return 0; } -int mgag200_device_init(struct mga_device *mdev, enum mga_type type, - const struct mgag200_device_info *info) +int mgag200_device_init(struct mga_device *mdev, + const struct mgag200_device_info *info, + const struct mgag200_device_funcs *funcs) { struct drm_device *dev = &mdev->base; u8 crtcext3, misc; int ret; mdev->info = info; - mdev->type = type; + mdev->funcs = funcs; ret = drmm_mutex_init(dev, &mdev->rmmio_lock); if (ret) @@ -226,29 +227,29 @@ mgag200_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) switch (type) { case G200_PCI: case G200_AGP: - mdev = mgag200_g200_device_create(pdev, &mgag200_driver, type); + mdev = mgag200_g200_device_create(pdev, &mgag200_driver); break; case G200_SE_A: case G200_SE_B: mdev = mgag200_g200se_device_create(pdev, &mgag200_driver, type); break; case G200_WB: - mdev = mgag200_g200wb_device_create(pdev, &mgag200_driver, type); + mdev = mgag200_g200wb_device_create(pdev, &mgag200_driver); break; case G200_EV: - mdev = mgag200_g200ev_device_create(pdev, &mgag200_driver, type); + mdev = mgag200_g200ev_device_create(pdev, &mgag200_driver); break; case G200_EH: - mdev = mgag200_g200eh_device_create(pdev, &mgag200_driver, type); + mdev = mgag200_g200eh_device_create(pdev, &mgag200_driver); break; case G200_EH3: - mdev = mgag200_g200eh3_device_create(pdev, &mgag200_driver, type); + mdev = mgag200_g200eh3_device_create(pdev, &mgag200_driver); break; case G200_ER: - mdev = mgag200_g200er_device_create(pdev, &mgag200_driver, type); + mdev = mgag200_g200er_device_create(pdev, &mgag200_driver); break; case G200_EW3: - mdev = mgag200_g200ew3_device_create(pdev, &mgag200_driver, type); + mdev = mgag200_g200ew3_device_create(pdev, &mgag200_driver); break; default: dev_err(&pdev->dev, "Device type %d is unsupported\n", type); diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index 301c4ab46539..f0c2349404b4 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -15,11 +15,13 @@ #include <video/vga.h> +#include <drm/drm_connector.h> +#include <drm/drm_crtc.h> #include <drm/drm_encoder.h> #include <drm/drm_fb_helper.h> #include <drm/drm_gem.h> #include <drm/drm_gem_shmem_helper.h> -#include <drm/drm_simple_kms_helper.h> +#include <drm/drm_plane.h> #include "mgag200_reg.h" @@ -123,11 +125,39 @@ #define MGA_MISC_OUT 0x1fc2 #define MGA_MISC_IN 0x1fcc +/* + * TODO: This is a pretty large set of default values for all kinds of + * settings. It should be split and set in the various DRM helpers, + * such as the CRTC reset or atomic_enable helpers. The PLL values + * probably belong to each model's PLL code. + */ +#define MGAG200_DAC_DEFAULT(xvrefctrl, xpixclkctrl, xmiscctrl, xsyspllm, xsysplln, xsyspllp) \ + /* 0x00: */ 0, 0, 0, 0, 0, 0, 0x00, 0, \ + /* 0x08: */ 0, 0, 0, 0, 0, 0, 0, 0, \ + /* 0x10: */ 0, 0, 0, 0, 0, 0, 0, 0, \ + /* 0x18: */ (xvrefctrl), \ + /* 0x19: */ 0, \ + /* 0x1a: */ (xpixclkctrl), \ + /* 0x1b: */ 0xff, 0xbf, 0x20, \ + /* 0x1e: */ (xmiscctrl), \ + /* 0x1f: */ 0x20, \ + /* 0x20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + /* 0x28: */ 0x00, 0x00, 0x00, 0x00, \ + /* 0x2c: */ (xsyspllm), \ + /* 0x2d: */ (xsysplln), \ + /* 0x2e: */ (xsyspllp), \ + /* 0x2f: */ 0x40, \ + /* 0x30: */ 0x00, 0xb0, 0x00, 0xc2, 0x34, 0x14, 0x02, 0x83, \ + /* 0x38: */ 0x00, 0x93, 0x00, 0x77, 0x00, 0x00, 0x00, 0x3a, \ + /* 0x40: */ 0, 0, 0, 0, 0, 0, 0, 0, \ + /* 0x48: */ 0, 0, 0, 0, 0, 0, 0, 0 \ + +#define MGAG200_LUT_SIZE 256 + #define MGAG200_MAX_FB_HEIGHT 4096 #define MGAG200_MAX_FB_WIDTH 4096 struct mga_device; -struct mgag200_pll; /* * Stores parameters for programming the PLLs @@ -146,20 +176,12 @@ struct mgag200_pll_values { unsigned int s; }; -struct mgag200_pll_funcs { - int (*compute)(struct mgag200_pll *pll, long clock, struct mgag200_pll_values *pllc); - void (*update)(struct mgag200_pll *pll, const struct mgag200_pll_values *pllc); -}; - -struct mgag200_pll { - struct mga_device *mdev; - - const struct mgag200_pll_funcs *funcs; -}; - struct mgag200_crtc_state { struct drm_crtc_state base; + /* Primary-plane format; required for modesetting and color mgmt. */ + const struct drm_format_info *format; + struct mgag200_pll_values pixpllc; }; @@ -188,8 +210,6 @@ enum mga_type { G200_EW3, }; -#define IS_G200_SE(mdev) (mdev->type == G200_SE_A || mdev->type == G200_SE_B) - struct mgag200_device_info { u16 max_hdisplay; u16 max_vdisplay; @@ -230,10 +250,39 @@ struct mgag200_device_info { .bug_no_startadd = (_bug_no_startadd), \ } +struct mgag200_device_funcs { + /* + * Disables an external reset source (i.e., BMC) before programming + * a new display mode. + */ + void (*disable_vidrst)(struct mga_device *mdev); + + /* + * Enables an external reset source (i.e., BMC) after programming + * a new display mode. + */ + void (*enable_vidrst)(struct mga_device *mdev); + + /* + * Validate that the given state can be programmed into PIXPLLC. On + * success, the calculated parameters should be stored in the CRTC's + * state in struct @mgag200_crtc_state.pixpllc. + */ + int (*pixpllc_atomic_check)(struct drm_crtc *crtc, struct drm_atomic_state *new_state); + + /* + * Program PIXPLLC from the CRTC state. The parameters should have been + * stored in struct @mgag200_crtc_state.pixpllc by the corresponding + * implementation of @pixpllc_atomic_check. + */ + void (*pixpllc_atomic_update)(struct drm_crtc *crtc, struct drm_atomic_state *old_state); +}; + struct mga_device { struct drm_device base; const struct mgag200_device_info *info; + const struct mgag200_device_funcs *funcs; struct resource *rmmio_res; void __iomem *rmmio; @@ -243,12 +292,11 @@ struct mga_device { void __iomem *vram; resource_size_t vram_available; - enum mga_type type; - - struct mgag200_pll pixpll; + struct drm_plane primary_plane; + struct drm_crtc crtc; + struct drm_encoder encoder; struct mga_i2c_chan i2c; struct drm_connector connector; - struct drm_simple_display_pipe display_pipe; }; static inline struct mga_device *to_mga_device(struct drm_device *dev) @@ -287,35 +335,113 @@ int mgag200_init_pci_options(struct pci_dev *pdev, u32 option, u32 option2); resource_size_t mgag200_probe_vram(void __iomem *mem, resource_size_t size); resource_size_t mgag200_device_probe_vram(struct mga_device *mdev); int mgag200_device_preinit(struct mga_device *mdev); -int mgag200_device_init(struct mga_device *mdev, enum mga_type type, - const struct mgag200_device_info *info); +int mgag200_device_init(struct mga_device *mdev, + const struct mgag200_device_info *info, + const struct mgag200_device_funcs *funcs); /* mgag200_<device type>.c */ -struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type); +struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct drm_driver *drv); struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const struct drm_driver *drv, enum mga_type type); -struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type); -struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type); -struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type); -struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type); -struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type); -struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type); +void mgag200_g200wb_init_registers(struct mga_device *mdev); +void mgag200_g200wb_pixpllc_atomic_update(struct drm_crtc *crtc, struct drm_atomic_state *old_state); +struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv); +struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv); +void mgag200_g200eh_init_registers(struct mga_device *mdev); +void mgag200_g200eh_pixpllc_atomic_update(struct drm_crtc *crtc, struct drm_atomic_state *old_state); +struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, + const struct drm_driver *drv); +struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, + const struct drm_driver *drv); +struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, + const struct drm_driver *drv); +struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev, + const struct drm_driver *drv); - /* mgag200_mode.c */ -resource_size_t mgag200_device_probe_vram(struct mga_device *mdev); -int mgag200_modeset_init(struct mga_device *mdev, resource_size_t vram_fb_available); +/* + * mgag200_mode.c + */ + +struct drm_crtc; +struct drm_crtc_state; +struct drm_display_mode; +struct drm_plane; +struct drm_atomic_state; + +extern const uint32_t mgag200_primary_plane_formats[]; +extern const size_t mgag200_primary_plane_formats_size; +extern const uint64_t mgag200_primary_plane_fmtmods[]; + +int mgag200_primary_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_atomic_state *new_state); +void mgag200_primary_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_state *old_state); +void mgag200_primary_plane_helper_atomic_disable(struct drm_plane *plane, + struct drm_atomic_state *old_state); +#define MGAG200_PRIMARY_PLANE_HELPER_FUNCS \ + DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, \ + .atomic_check = mgag200_primary_plane_helper_atomic_check, \ + .atomic_update = mgag200_primary_plane_helper_atomic_update, \ + .atomic_disable = mgag200_primary_plane_helper_atomic_disable + +#define MGAG200_PRIMARY_PLANE_FUNCS \ + .update_plane = drm_atomic_helper_update_plane, \ + .disable_plane = drm_atomic_helper_disable_plane, \ + .destroy = drm_plane_cleanup, \ + DRM_GEM_SHADOW_PLANE_FUNCS + +enum drm_mode_status mgag200_crtc_helper_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode); +int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *new_state); +void mgag200_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *old_state); +void mgag200_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *old_state); +void mgag200_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *old_state); + +#define MGAG200_CRTC_HELPER_FUNCS \ + .mode_valid = mgag200_crtc_helper_mode_valid, \ + .atomic_check = mgag200_crtc_helper_atomic_check, \ + .atomic_flush = mgag200_crtc_helper_atomic_flush, \ + .atomic_enable = mgag200_crtc_helper_atomic_enable, \ + .atomic_disable = mgag200_crtc_helper_atomic_disable + +void mgag200_crtc_reset(struct drm_crtc *crtc); +struct drm_crtc_state *mgag200_crtc_atomic_duplicate_state(struct drm_crtc *crtc); +void mgag200_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state); + +#define MGAG200_CRTC_FUNCS \ + .reset = mgag200_crtc_reset, \ + .destroy = drm_crtc_cleanup, \ + .set_config = drm_atomic_helper_set_config, \ + .page_flip = drm_atomic_helper_page_flip, \ + .atomic_duplicate_state = mgag200_crtc_atomic_duplicate_state, \ + .atomic_destroy_state = mgag200_crtc_atomic_destroy_state + +#define MGAG200_DAC_ENCODER_FUNCS \ + .destroy = drm_encoder_cleanup + +int mgag200_vga_connector_helper_get_modes(struct drm_connector *connector); + +#define MGAG200_VGA_CONNECTOR_HELPER_FUNCS \ + .get_modes = mgag200_vga_connector_helper_get_modes + +#define MGAG200_VGA_CONNECTOR_FUNCS \ + .reset = drm_atomic_helper_connector_reset, \ + .fill_modes = drm_helper_probe_single_connector_modes, \ + .destroy = drm_connector_cleanup, \ + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, \ + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state + +void mgag200_set_mode_regs(struct mga_device *mdev, const struct drm_display_mode *mode); +void mgag200_set_format_regs(struct mga_device *mdev, const struct drm_format_info *format); +void mgag200_enable_display(struct mga_device *mdev); +void mgag200_init_registers(struct mga_device *mdev); +int mgag200_mode_config_init(struct mga_device *mdev, resource_size_t vram_available); + + /* mgag200_bmc.c */ +void mgag200_bmc_disable_vidrst(struct mga_device *mdev); +void mgag200_bmc_enable_vidrst(struct mga_device *mdev); /* mgag200_i2c.c */ int mgag200_i2c_init(struct mga_device *mdev, struct mga_i2c_chan *i2c); - /* mgag200_pll.c */ -int mgag200_pixpll_init(struct mgag200_pll *pixpll, struct mga_device *mdev); - #endif /* __MGAG200_DRV_H__ */ diff --git a/drivers/gpu/drm/mgag200/mgag200_g200.c b/drivers/gpu/drm/mgag200/mgag200_g200.c index 674385921b7f..bf5d7fe525a3 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200.c @@ -3,7 +3,11 @@ #include <linux/pci.h> #include <linux/vmalloc.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> +#include <drm/drm_gem_atomic_helper.h> +#include <drm/drm_probe_helper.h> #include "mgag200_drv.h" @@ -30,6 +34,235 @@ static int mgag200_g200_init_pci_options(struct pci_dev *pdev) return mgag200_init_pci_options(pdev, option, 0x00008000); } +static void mgag200_g200_init_registers(struct mgag200_g200_device *g200) +{ + static const u8 dacvalue[] = { + MGAG200_DAC_DEFAULT(0x00, 0xc9, 0x1f, + 0x04, 0x2d, 0x19) + }; + + struct mga_device *mdev = &g200->base; + size_t i; + + for (i = 0; i < ARRAY_SIZE(dacvalue); ++i) { + if ((i <= 0x17) || + (i == 0x1b) || + (i == 0x1c) || + ((i >= 0x1f) && (i <= 0x29)) || + ((i >= 0x30) && (i <= 0x37))) + continue; + WREG_DAC(i, dacvalue[i]); + } + + mgag200_init_registers(mdev); +} + +/* + * PIXPLLC + */ + +static int mgag200_g200_pixpllc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *new_state) +{ + static const int post_div_max = 7; + static const int in_div_min = 1; + static const int in_div_max = 6; + static const int feed_div_min = 7; + static const int feed_div_max = 127; + + struct drm_device *dev = crtc->dev; + struct mgag200_g200_device *g200 = to_mgag200_g200_device(dev); + struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); + struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state); + long clock = new_crtc_state->mode.clock; + struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc; + u8 testp, testm, testn; + u8 n = 0, m = 0, p, s; + long f_vco; + long computed; + long delta, tmp_delta; + long ref_clk = g200->ref_clk; + long p_clk_min = g200->pclk_min; + long p_clk_max = g200->pclk_max; + + if (clock > p_clk_max) { + drm_err(dev, "Pixel Clock %ld too high\n", clock); + return -EINVAL; + } + + if (clock < p_clk_min >> 3) + clock = p_clk_min >> 3; + + f_vco = clock; + for (testp = 0; + testp <= post_div_max && f_vco < p_clk_min; + testp = (testp << 1) + 1, f_vco <<= 1) + ; + p = testp + 1; + + delta = clock; + + for (testm = in_div_min; testm <= in_div_max; testm++) { + for (testn = feed_div_min; testn <= feed_div_max; testn++) { + computed = ref_clk * (testn + 1) / (testm + 1); + if (computed < f_vco) + tmp_delta = f_vco - computed; + else + tmp_delta = computed - f_vco; + if (tmp_delta < delta) { + delta = tmp_delta; + m = testm + 1; + n = testn + 1; + } + } + } + f_vco = ref_clk * n / m; + if (f_vco < 100000) + s = 0; + else if (f_vco < 140000) + s = 1; + else if (f_vco < 180000) + s = 2; + else + s = 3; + + drm_dbg_kms(dev, "clock: %ld vco: %ld m: %d n: %d p: %d s: %d\n", + clock, f_vco, m, n, p, s); + + pixpllc->m = m; + pixpllc->n = n; + pixpllc->p = p; + pixpllc->s = s; + + return 0; +} + +static void mgag200_g200_pixpllc_atomic_update(struct drm_crtc *crtc, + struct drm_atomic_state *old_state) +{ + struct drm_device *dev = crtc->dev; + struct mga_device *mdev = to_mga_device(dev); + struct drm_crtc_state *crtc_state = crtc->state; + struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); + struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc; + unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; + u8 xpixpllcm, xpixpllcn, xpixpllcp; + + pixpllcm = pixpllc->m - 1; + pixpllcn = pixpllc->n - 1; + pixpllcp = pixpllc->p - 1; + pixpllcs = pixpllc->s; + + xpixpllcm = pixpllcm; + xpixpllcn = pixpllcn; + xpixpllcp = (pixpllcs << 3) | pixpllcp; + + WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); + + WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm); + WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn); + WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp); +} + +/* + * Mode-setting pipeline + */ + +static const struct drm_plane_helper_funcs mgag200_g200_primary_plane_helper_funcs = { + MGAG200_PRIMARY_PLANE_HELPER_FUNCS, +}; + +static const struct drm_plane_funcs mgag200_g200_primary_plane_funcs = { + MGAG200_PRIMARY_PLANE_FUNCS, +}; + +static const struct drm_crtc_helper_funcs mgag200_g200_crtc_helper_funcs = { + MGAG200_CRTC_HELPER_FUNCS, +}; + +static const struct drm_crtc_funcs mgag200_g200_crtc_funcs = { + MGAG200_CRTC_FUNCS, +}; + +static const struct drm_encoder_funcs mgag200_g200_dac_encoder_funcs = { + MGAG200_DAC_ENCODER_FUNCS, +}; + +static const struct drm_connector_helper_funcs mgag200_g200_vga_connector_helper_funcs = { + MGAG200_VGA_CONNECTOR_HELPER_FUNCS, +}; + +static const struct drm_connector_funcs mgag200_g200_vga_connector_funcs = { + MGAG200_VGA_CONNECTOR_FUNCS, +}; + +static int mgag200_g200_pipeline_init(struct mga_device *mdev) +{ + struct drm_device *dev = &mdev->base; + struct drm_plane *primary_plane = &mdev->primary_plane; + struct drm_crtc *crtc = &mdev->crtc; + struct drm_encoder *encoder = &mdev->encoder; + struct mga_i2c_chan *i2c = &mdev->i2c; + struct drm_connector *connector = &mdev->connector; + int ret; + + ret = drm_universal_plane_init(dev, primary_plane, 0, + &mgag200_g200_primary_plane_funcs, + mgag200_primary_plane_formats, + mgag200_primary_plane_formats_size, + mgag200_primary_plane_fmtmods, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) { + drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret); + return ret; + } + drm_plane_helper_add(primary_plane, &mgag200_g200_primary_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(primary_plane); + + ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, + &mgag200_g200_crtc_funcs, NULL); + if (ret) { + drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret); + return ret; + } + drm_crtc_helper_add(crtc, &mgag200_g200_crtc_helper_funcs); + + /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */ + drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE); + drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE); + + encoder->possible_crtcs = drm_crtc_mask(crtc); + ret = drm_encoder_init(dev, encoder, &mgag200_g200_dac_encoder_funcs, + DRM_MODE_ENCODER_DAC, NULL); + if (ret) { + drm_err(dev, "drm_encoder_init() failed: %d\n", ret); + return ret; + } + + ret = mgag200_i2c_init(mdev, i2c); + if (ret) { + drm_err(dev, "failed to add DDC bus: %d\n", ret); + return ret; + } + + ret = drm_connector_init_with_ddc(dev, connector, + &mgag200_g200_vga_connector_funcs, + DRM_MODE_CONNECTOR_VGA, + &i2c->adapter); + if (ret) { + drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret); + return ret; + } + drm_connector_helper_add(connector, &mgag200_g200_vga_connector_helper_funcs); + + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) { + drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret); + return ret; + } + + return 0; +} + /* * DRM Device */ @@ -160,8 +393,12 @@ out: pci_unmap_rom(pdev, rom); } -struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type) +static const struct mgag200_device_funcs mgag200_g200_device_funcs = { + .pixpllc_atomic_check = mgag200_g200_pixpllc_atomic_check, + .pixpllc_atomic_update = mgag200_g200_pixpllc_atomic_update, +}; + +struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct drm_driver *drv) { struct mgag200_g200_device *g200; struct mga_device *mdev; @@ -187,15 +424,24 @@ struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct mgag200_g200_init_refclk(g200); - ret = mgag200_device_init(mdev, type, &mgag200_g200_device_info); + ret = mgag200_device_init(mdev, &mgag200_g200_device_info, + &mgag200_g200_device_funcs); if (ret) return ERR_PTR(ret); + mgag200_g200_init_registers(g200); + vram_available = mgag200_device_probe_vram(mdev); - ret = mgag200_modeset_init(mdev, vram_available); + ret = mgag200_mode_config_init(mdev, vram_available); if (ret) return ERR_PTR(ret); + ret = mgag200_g200_pipeline_init(mdev); + if (ret) + return ERR_PTR(ret); + + drm_mode_config_reset(dev); + return mdev; } diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh.c b/drivers/gpu/drm/mgag200/mgag200_g200eh.c index 1b9a22728744..fad62453a91d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200eh.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh.c @@ -1,11 +1,267 @@ // SPDX-License-Identifier: GPL-2.0-only +#include <linux/delay.h> #include <linux/pci.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> +#include <drm/drm_gem_atomic_helper.h> +#include <drm/drm_probe_helper.h> #include "mgag200_drv.h" +void mgag200_g200eh_init_registers(struct mga_device *mdev) +{ + static const u8 dacvalue[] = { + MGAG200_DAC_DEFAULT(0x00, 0xc9, + MGA1064_MISC_CTL_VGA8 | MGA1064_MISC_CTL_DAC_RAM_CS, + 0x00, 0x00, 0x00) + }; + + size_t i; + + for (i = 0; i < ARRAY_SIZE(dacvalue); i++) { + if ((i <= 0x17) || + (i == 0x1b) || + (i == 0x1c) || + ((i >= 0x1f) && (i <= 0x29)) || + ((i >= 0x30) && (i <= 0x37)) || + ((i >= 0x44) && (i <= 0x4e))) + continue; + WREG_DAC(i, dacvalue[i]); + } + + mgag200_init_registers(mdev); +} + +/* + * PIXPLLC + */ + +static int mgag200_g200eh_pixpllc_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_state *new_state) +{ + static const unsigned int vcomax = 800000; + static const unsigned int vcomin = 400000; + static const unsigned int pllreffreq = 33333; + + struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); + struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state); + long clock = new_crtc_state->mode.clock; + struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc; + unsigned int delta, tmpdelta; + unsigned int testp, testm, testn; + unsigned int p, m, n, s; + unsigned int computed; + + m = n = p = s = 0; + delta = 0xffffffff; + + for (testp = 16; testp > 0; testp >>= 1) { + if (clock * testp > vcomax) + continue; + if (clock * testp < vcomin) + continue; + + for (testm = 1; testm < 33; testm++) { + for (testn = 17; testn < 257; testn++) { + computed = (pllreffreq * testn) / (testm * testp); + if (computed > clock) + tmpdelta = computed - clock; + else + tmpdelta = clock - computed; + if (tmpdelta < delta) { + delta = tmpdelta; + n = testn; + m = testm; + p = testp; + } + } + } + } + + pixpllc->m = m; + pixpllc->n = n; + pixpllc->p = p; + pixpllc->s = s; + + return 0; +} + +void mgag200_g200eh_pixpllc_atomic_update(struct drm_crtc *crtc, + struct drm_atomic_state *old_state) +{ + struct drm_device *dev = crtc->dev; + struct mga_device *mdev = to_mga_device(dev); + struct drm_crtc_state *crtc_state = crtc->state; + struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); + struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc; + unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; + u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; + int i, j, tmpcount, vcount; + bool pll_locked = false; + + pixpllcm = pixpllc->m - 1; + pixpllcn = pixpllc->n - 1; + pixpllcp = pixpllc->p - 1; + pixpllcs = pixpllc->s; + + xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm; + xpixpllcn = pixpllcn; + xpixpllcp = (pixpllcs << 3) | pixpllcp; + + WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); + + for (i = 0; i <= 32 && pll_locked == false; i++) { + WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); + tmp = RREG8(DAC_DATA); + tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; + WREG8(DAC_DATA, tmp); + + tmp = RREG8(MGAREG_MEM_MISC_READ); + tmp |= 0x3 << 2; + WREG8(MGAREG_MEM_MISC_WRITE, tmp); + + WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); + tmp = RREG8(DAC_DATA); + tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; + WREG8(DAC_DATA, tmp); + + udelay(500); + + WREG_DAC(MGA1064_EH_PIX_PLLC_M, xpixpllcm); + WREG_DAC(MGA1064_EH_PIX_PLLC_N, xpixpllcn); + WREG_DAC(MGA1064_EH_PIX_PLLC_P, xpixpllcp); + + udelay(500); + + WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); + tmp = RREG8(DAC_DATA); + tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; + tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; + WREG8(DAC_DATA, tmp); + + WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); + tmp = RREG8(DAC_DATA); + tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; + tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; + WREG8(DAC_DATA, tmp); + + vcount = RREG8(MGAREG_VCOUNT); + + for (j = 0; j < 30 && pll_locked == false; j++) { + tmpcount = RREG8(MGAREG_VCOUNT); + if (tmpcount < vcount) + vcount = 0; + if ((tmpcount - vcount) > 2) + pll_locked = true; + else + udelay(5); + } + } +} + +/* + * Mode-setting pipeline + */ + +static const struct drm_plane_helper_funcs mgag200_g200eh_primary_plane_helper_funcs = { + MGAG200_PRIMARY_PLANE_HELPER_FUNCS, +}; + +static const struct drm_plane_funcs mgag200_g200eh_primary_plane_funcs = { + MGAG200_PRIMARY_PLANE_FUNCS, +}; + +static const struct drm_crtc_helper_funcs mgag200_g200eh_crtc_helper_funcs = { + MGAG200_CRTC_HELPER_FUNCS, +}; + +static const struct drm_crtc_funcs mgag200_g200eh_crtc_funcs = { + MGAG200_CRTC_FUNCS, +}; + +static const struct drm_encoder_funcs mgag200_g200eh_dac_encoder_funcs = { + MGAG200_DAC_ENCODER_FUNCS, +}; + +static const struct drm_connector_helper_funcs mgag200_g200eh_vga_connector_helper_funcs = { + MGAG200_VGA_CONNECTOR_HELPER_FUNCS, +}; + +static const struct drm_connector_funcs mgag200_g200eh_vga_connector_funcs = { + MGAG200_VGA_CONNECTOR_FUNCS, +}; + +static int mgag200_g200eh_pipeline_init(struct mga_device *mdev) +{ + struct drm_device *dev = &mdev->base; + struct drm_plane *primary_plane = &mdev->primary_plane; + struct drm_crtc *crtc = &mdev->crtc; + struct drm_encoder *encoder = &mdev->encoder; + struct mga_i2c_chan *i2c = &mdev->i2c; + struct drm_connector *connector = &mdev->connector; + int ret; + + ret = drm_universal_plane_init(dev, primary_plane, 0, + &mgag200_g200eh_primary_plane_funcs, + mgag200_primary_plane_formats, + mgag200_primary_plane_formats_size, + mgag200_primary_plane_fmtmods, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) { + drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret); + return ret; + } + drm_plane_helper_add(primary_plane, &mgag200_g200eh_primary_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(primary_plane); + + ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, + &mgag200_g200eh_crtc_funcs, NULL); + if (ret) { + drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret); + return ret; + } + drm_crtc_helper_add(crtc, &mgag200_g200eh_crtc_helper_funcs); + + /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */ + drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE); + drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE); + + encoder->possible_crtcs = drm_crtc_mask(crtc); + ret = drm_encoder_init(dev, encoder, &mgag200_g200eh_dac_encoder_funcs, + DRM_MODE_ENCODER_DAC, NULL); + if (ret) { + drm_err(dev, "drm_encoder_init() failed: %d\n", ret); + return ret; + } + + ret = mgag200_i2c_init(mdev, i2c); + if (ret) { + drm_err(dev, "failed to add DDC bus: %d\n", ret); + return ret; + } + + ret = drm_connector_init_with_ddc(dev, connector, + &mgag200_g200eh_vga_connector_funcs, + DRM_MODE_CONNECTOR_VGA, + &i2c->adapter); + if (ret) { + drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret); + return ret; + } + drm_connector_helper_add(connector, &mgag200_g200eh_vga_connector_helper_funcs); + + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) { + drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret); + return ret; + } + + return 0; +} + /* * DRM device */ @@ -13,8 +269,12 @@ static const struct mgag200_device_info mgag200_g200eh_device_info = MGAG200_DEVICE_INFO_INIT(2048, 2048, 37500, false, 1, 0, false); -struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type) +static const struct mgag200_device_funcs mgag200_g200eh_device_funcs = { + .pixpllc_atomic_check = mgag200_g200eh_pixpllc_atomic_check, + .pixpllc_atomic_update = mgag200_g200eh_pixpllc_atomic_update, +}; + +struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv) { struct mga_device *mdev; struct drm_device *dev; @@ -36,15 +296,24 @@ struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const stru if (ret) return ERR_PTR(ret); - ret = mgag200_device_init(mdev, type, &mgag200_g200eh_device_info); + ret = mgag200_device_init(mdev, &mgag200_g200eh_device_info, + &mgag200_g200eh_device_funcs); if (ret) return ERR_PTR(ret); + mgag200_g200eh_init_registers(mdev); + vram_available = mgag200_device_probe_vram(mdev); - ret = mgag200_modeset_init(mdev, vram_available); + ret = mgag200_mode_config_init(mdev, vram_available); if (ret) return ERR_PTR(ret); + ret = mgag200_g200eh_pipeline_init(mdev); + if (ret) + return ERR_PTR(ret); + + drm_mode_config_reset(dev); + return mdev; } diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c index 438cda1b14c9..0f7d8112cd49 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c @@ -2,20 +2,184 @@ #include <linux/pci.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> +#include <drm/drm_gem_atomic_helper.h> +#include <drm/drm_probe_helper.h> #include "mgag200_drv.h" /* + * PIXPLLC + */ + +static int mgag200_g200eh3_pixpllc_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_state *new_state) +{ + static const unsigned int vcomax = 3000000; + static const unsigned int vcomin = 1500000; + static const unsigned int pllreffreq = 25000; + + struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); + struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state); + long clock = new_crtc_state->mode.clock; + struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc; + unsigned int delta, tmpdelta; + unsigned int testp, testm, testn; + unsigned int p, m, n, s; + unsigned int computed; + + m = n = p = s = 0; + delta = 0xffffffff; + testp = 0; + + for (testm = 150; testm >= 6; testm--) { + if (clock * testm > vcomax) + continue; + if (clock * testm < vcomin) + continue; + for (testn = 120; testn >= 60; testn--) { + computed = (pllreffreq * testn) / testm; + if (computed > clock) + tmpdelta = computed - clock; + else + tmpdelta = clock - computed; + if (tmpdelta < delta) { + delta = tmpdelta; + n = testn + 1; + m = testm + 1; + p = testp + 1; + } + if (delta == 0) + break; + } + if (delta == 0) + break; + } + + pixpllc->m = m; + pixpllc->n = n; + pixpllc->p = p; + pixpllc->s = s; + + return 0; +} + +/* + * Mode-setting pipeline + */ + +static const struct drm_plane_helper_funcs mgag200_g200eh3_primary_plane_helper_funcs = { + MGAG200_PRIMARY_PLANE_HELPER_FUNCS, +}; + +static const struct drm_plane_funcs mgag200_g200eh3_primary_plane_funcs = { + MGAG200_PRIMARY_PLANE_FUNCS, +}; + +static const struct drm_crtc_helper_funcs mgag200_g200eh3_crtc_helper_funcs = { + MGAG200_CRTC_HELPER_FUNCS, +}; + +static const struct drm_crtc_funcs mgag200_g200eh3_crtc_funcs = { + MGAG200_CRTC_FUNCS, +}; + +static const struct drm_encoder_funcs mgag200_g200eh3_dac_encoder_funcs = { + MGAG200_DAC_ENCODER_FUNCS, +}; + +static const struct drm_connector_helper_funcs mgag200_g200eh3_vga_connector_helper_funcs = { + MGAG200_VGA_CONNECTOR_HELPER_FUNCS, +}; + +static const struct drm_connector_funcs mgag200_g200eh3_vga_connector_funcs = { + MGAG200_VGA_CONNECTOR_FUNCS, +}; + +static int mgag200_g200eh3_pipeline_init(struct mga_device *mdev) +{ + struct drm_device *dev = &mdev->base; + struct drm_plane *primary_plane = &mdev->primary_plane; + struct drm_crtc *crtc = &mdev->crtc; + struct drm_encoder *encoder = &mdev->encoder; + struct mga_i2c_chan *i2c = &mdev->i2c; + struct drm_connector *connector = &mdev->connector; + int ret; + + ret = drm_universal_plane_init(dev, primary_plane, 0, + &mgag200_g200eh3_primary_plane_funcs, + mgag200_primary_plane_formats, + mgag200_primary_plane_formats_size, + mgag200_primary_plane_fmtmods, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) { + drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret); + return ret; + } + drm_plane_helper_add(primary_plane, &mgag200_g200eh3_primary_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(primary_plane); + + ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, + &mgag200_g200eh3_crtc_funcs, NULL); + if (ret) { + drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret); + return ret; + } + drm_crtc_helper_add(crtc, &mgag200_g200eh3_crtc_helper_funcs); + + /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */ + drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE); + drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE); + + encoder->possible_crtcs = drm_crtc_mask(crtc); + ret = drm_encoder_init(dev, encoder, &mgag200_g200eh3_dac_encoder_funcs, + DRM_MODE_ENCODER_DAC, NULL); + if (ret) { + drm_err(dev, "drm_encoder_init() failed: %d\n", ret); + return ret; + } + + ret = mgag200_i2c_init(mdev, i2c); + if (ret) { + drm_err(dev, "failed to add DDC bus: %d\n", ret); + return ret; + } + + ret = drm_connector_init_with_ddc(dev, connector, + &mgag200_g200eh3_vga_connector_funcs, + DRM_MODE_CONNECTOR_VGA, + &i2c->adapter); + if (ret) { + drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret); + return ret; + } + drm_connector_helper_add(connector, &mgag200_g200eh3_vga_connector_helper_funcs); + + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) { + drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret); + return ret; + } + + return 0; +} + +/* * DRM device */ static const struct mgag200_device_info mgag200_g200eh3_device_info = MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false, 1, 0, false); +static const struct mgag200_device_funcs mgag200_g200eh3_device_funcs = { + .pixpllc_atomic_check = mgag200_g200eh3_pixpllc_atomic_check, + .pixpllc_atomic_update = mgag200_g200eh_pixpllc_atomic_update, // same as G200EH +}; + struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, - const struct drm_driver *drv, - enum mga_type type) + const struct drm_driver *drv) { struct mga_device *mdev; struct drm_device *dev; @@ -37,15 +201,24 @@ struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, if (ret) return ERR_PTR(ret); - ret = mgag200_device_init(mdev, type, &mgag200_g200eh3_device_info); + ret = mgag200_device_init(mdev, &mgag200_g200eh3_device_info, + &mgag200_g200eh3_device_funcs); if (ret) return ERR_PTR(ret); + mgag200_g200eh_init_registers(mdev); // same as G200EH + vram_available = mgag200_device_probe_vram(mdev); - ret = mgag200_modeset_init(mdev, vram_available); + ret = mgag200_mode_config_init(mdev, vram_available); if (ret) return ERR_PTR(ret); + ret = mgag200_g200eh3_pipeline_init(mdev); + if (ret) + return ERR_PTR(ret); + + drm_mode_config_reset(dev); + return mdev; } diff --git a/drivers/gpu/drm/mgag200/mgag200_g200er.c b/drivers/gpu/drm/mgag200/mgag200_g200er.c index 0790d4e6463d..bce267e0f7de 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200er.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200er.c @@ -1,11 +1,305 @@ // SPDX-License-Identifier: GPL-2.0-only +#include <linux/delay.h> #include <linux/pci.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> +#include <drm/drm_gem_atomic_helper.h> +#include <drm/drm_probe_helper.h> #include "mgag200_drv.h" +static void mgag200_g200er_init_registers(struct mga_device *mdev) +{ + static const u8 dacvalue[] = { + MGAG200_DAC_DEFAULT(0x00, 0xc9, 0x1f, 0x00, 0x00, 0x00) + }; + + size_t i; + + for (i = 0; i < ARRAY_SIZE(dacvalue); i++) { + if ((i <= 0x17) || + (i == 0x1b) || + (i == 0x1c) || + ((i >= 0x1f) && (i <= 0x29)) || + ((i >= 0x30) && (i <= 0x37))) + continue; + WREG_DAC(i, dacvalue[i]); + } + + WREG_DAC(0x90, 0); /* G200ER specific */ + + mgag200_init_registers(mdev); + + WREG_ECRT(0x24, 0x5); /* G200ER specific */ +} + +static void mgag200_g200er_reset_tagfifo(struct mga_device *mdev) +{ + static const uint32_t RESET_FLAG = 0x00200000; /* undocumented magic value */ + u32 memctl; + + memctl = RREG32(MGAREG_MEMCTL); + + memctl |= RESET_FLAG; + WREG32(MGAREG_MEMCTL, memctl); + + udelay(1000); + + memctl &= ~RESET_FLAG; + WREG32(MGAREG_MEMCTL, memctl); +} + +/* + * PIXPLLC + */ + +static int mgag200_g200er_pixpllc_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_state *new_state) +{ + static const unsigned int vcomax = 1488000; + static const unsigned int vcomin = 1056000; + static const unsigned int pllreffreq = 48000; + static const unsigned int m_div_val[] = { 1, 2, 4, 8 }; + + struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); + struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state); + long clock = new_crtc_state->mode.clock; + struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc; + unsigned int delta, tmpdelta; + int testr, testn, testm, testo; + unsigned int p, m, n, s; + unsigned int computed, vco; + + m = n = p = s = 0; + delta = 0xffffffff; + + for (testr = 0; testr < 4; testr++) { + if (delta == 0) + break; + for (testn = 5; testn < 129; testn++) { + if (delta == 0) + break; + for (testm = 3; testm >= 0; testm--) { + if (delta == 0) + break; + for (testo = 5; testo < 33; testo++) { + vco = pllreffreq * (testn + 1) / + (testr + 1); + if (vco < vcomin) + continue; + if (vco > vcomax) + continue; + computed = vco / (m_div_val[testm] * (testo + 1)); + if (computed > clock) + tmpdelta = computed - clock; + else + tmpdelta = clock - computed; + if (tmpdelta < delta) { + delta = tmpdelta; + m = (testm | (testo << 3)) + 1; + n = testn + 1; + p = testr + 1; + s = testr; + } + } + } + } + } + + pixpllc->m = m; + pixpllc->n = n; + pixpllc->p = p; + pixpllc->s = s; + + return 0; +} + +static void mgag200_g200er_pixpllc_atomic_update(struct drm_crtc *crtc, + struct drm_atomic_state *old_state) +{ + struct drm_device *dev = crtc->dev; + struct mga_device *mdev = to_mga_device(dev); + struct drm_crtc_state *crtc_state = crtc->state; + struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); + struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc; + unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; + u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; + + pixpllcm = pixpllc->m - 1; + pixpllcn = pixpllc->n - 1; + pixpllcp = pixpllc->p - 1; + pixpllcs = pixpllc->s; + + xpixpllcm = pixpllcm; + xpixpllcn = pixpllcn; + xpixpllcp = (pixpllcs << 3) | pixpllcp; + + WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); + + WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); + tmp = RREG8(DAC_DATA); + tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; + WREG8(DAC_DATA, tmp); + + WREG8(DAC_INDEX, MGA1064_REMHEADCTL); + tmp = RREG8(DAC_DATA); + tmp |= MGA1064_REMHEADCTL_CLKDIS; + WREG8(DAC_DATA, tmp); + + tmp = RREG8(MGAREG_MEM_MISC_READ); + tmp |= (0x3<<2) | 0xc0; + WREG8(MGAREG_MEM_MISC_WRITE, tmp); + + WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); + tmp = RREG8(DAC_DATA); + tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; + tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; + WREG8(DAC_DATA, tmp); + + udelay(500); + + WREG_DAC(MGA1064_ER_PIX_PLLC_N, xpixpllcn); + WREG_DAC(MGA1064_ER_PIX_PLLC_M, xpixpllcm); + WREG_DAC(MGA1064_ER_PIX_PLLC_P, xpixpllcp); + + udelay(50); +} + +/* + * Mode-setting pipeline + */ + +static const struct drm_plane_helper_funcs mgag200_g200er_primary_plane_helper_funcs = { + MGAG200_PRIMARY_PLANE_HELPER_FUNCS, +}; + +static const struct drm_plane_funcs mgag200_g200er_primary_plane_funcs = { + MGAG200_PRIMARY_PLANE_FUNCS, +}; + +static void mgag200_g200er_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_state *old_state) +{ + struct drm_device *dev = crtc->dev; + struct mga_device *mdev = to_mga_device(dev); + const struct mgag200_device_funcs *funcs = mdev->funcs; + struct drm_crtc_state *crtc_state = crtc->state; + struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; + struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); + const struct drm_format_info *format = mgag200_crtc_state->format; + + if (funcs->disable_vidrst) + funcs->disable_vidrst(mdev); + + mgag200_set_format_regs(mdev, format); + mgag200_set_mode_regs(mdev, adjusted_mode); + + if (funcs->pixpllc_atomic_update) + funcs->pixpllc_atomic_update(crtc, old_state); + + mgag200_g200er_reset_tagfifo(mdev); + + mgag200_enable_display(mdev); + + if (funcs->enable_vidrst) + funcs->enable_vidrst(mdev); +} + +static const struct drm_crtc_helper_funcs mgag200_g200er_crtc_helper_funcs = { + .mode_valid = mgag200_crtc_helper_mode_valid, + .atomic_check = mgag200_crtc_helper_atomic_check, + .atomic_flush = mgag200_crtc_helper_atomic_flush, + .atomic_enable = mgag200_g200er_crtc_helper_atomic_enable, + .atomic_disable = mgag200_crtc_helper_atomic_disable +}; + +static const struct drm_crtc_funcs mgag200_g200er_crtc_funcs = { + MGAG200_CRTC_FUNCS, +}; + +static const struct drm_encoder_funcs mgag200_g200er_dac_encoder_funcs = { + MGAG200_DAC_ENCODER_FUNCS, +}; + +static const struct drm_connector_helper_funcs mgag200_g200er_vga_connector_helper_funcs = { + MGAG200_VGA_CONNECTOR_HELPER_FUNCS, +}; + +static const struct drm_connector_funcs mgag200_g200er_vga_connector_funcs = { + MGAG200_VGA_CONNECTOR_FUNCS, +}; + +static int mgag200_g200er_pipeline_init(struct mga_device *mdev) +{ + struct drm_device *dev = &mdev->base; + struct drm_plane *primary_plane = &mdev->primary_plane; + struct drm_crtc *crtc = &mdev->crtc; + struct drm_encoder *encoder = &mdev->encoder; + struct mga_i2c_chan *i2c = &mdev->i2c; + struct drm_connector *connector = &mdev->connector; + int ret; + + ret = drm_universal_plane_init(dev, primary_plane, 0, + &mgag200_g200er_primary_plane_funcs, + mgag200_primary_plane_formats, + mgag200_primary_plane_formats_size, + mgag200_primary_plane_fmtmods, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) { + drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret); + return ret; + } + drm_plane_helper_add(primary_plane, &mgag200_g200er_primary_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(primary_plane); + + ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, + &mgag200_g200er_crtc_funcs, NULL); + if (ret) { + drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret); + return ret; + } + drm_crtc_helper_add(crtc, &mgag200_g200er_crtc_helper_funcs); + + /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */ + drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE); + drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE); + + encoder->possible_crtcs = drm_crtc_mask(crtc); + ret = drm_encoder_init(dev, encoder, &mgag200_g200er_dac_encoder_funcs, + DRM_MODE_ENCODER_DAC, NULL); + if (ret) { + drm_err(dev, "drm_encoder_init() failed: %d\n", ret); + return ret; + } + + ret = mgag200_i2c_init(mdev, i2c); + if (ret) { + drm_err(dev, "failed to add DDC bus: %d\n", ret); + return ret; + } + + ret = drm_connector_init_with_ddc(dev, connector, + &mgag200_g200er_vga_connector_funcs, + DRM_MODE_CONNECTOR_VGA, + &i2c->adapter); + if (ret) { + drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret); + return ret; + } + drm_connector_helper_add(connector, &mgag200_g200er_vga_connector_helper_funcs); + + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) { + drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret); + return ret; + } + + return 0; +} + /* * DRM device */ @@ -13,8 +307,12 @@ static const struct mgag200_device_info mgag200_g200er_device_info = MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, 1, 0, false); -struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type) +static const struct mgag200_device_funcs mgag200_g200er_device_funcs = { + .pixpllc_atomic_check = mgag200_g200er_pixpllc_atomic_check, + .pixpllc_atomic_update = mgag200_g200er_pixpllc_atomic_update, +}; + +struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const struct drm_driver *drv) { struct mga_device *mdev; struct drm_device *dev; @@ -32,15 +330,24 @@ struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const stru if (ret) return ERR_PTR(ret); - ret = mgag200_device_init(mdev, type, &mgag200_g200er_device_info); + ret = mgag200_device_init(mdev, &mgag200_g200er_device_info, + &mgag200_g200er_device_funcs); if (ret) return ERR_PTR(ret); + mgag200_g200er_init_registers(mdev); + vram_available = mgag200_device_probe_vram(mdev); - ret = mgag200_modeset_init(mdev, vram_available); + ret = mgag200_mode_config_init(mdev, vram_available); if (ret) return ERR_PTR(ret); + ret = mgag200_g200er_pipeline_init(mdev); + if (ret) + return ERR_PTR(ret); + + drm_mode_config_reset(dev); + return mdev; } diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ev.c b/drivers/gpu/drm/mgag200/mgag200_g200ev.c index 5353422d0eef..ac957f42abe1 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ev.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ev.c @@ -1,11 +1,306 @@ // SPDX-License-Identifier: GPL-2.0-only +#include <linux/delay.h> #include <linux/pci.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> +#include <drm/drm_gem_atomic_helper.h> +#include <drm/drm_probe_helper.h> #include "mgag200_drv.h" +static void mgag200_g200ev_init_registers(struct mga_device *mdev) +{ + static const u8 dacvalue[] = { + MGAG200_DAC_DEFAULT(0x00, + MGA1064_PIX_CLK_CTL_SEL_PLL, + MGA1064_MISC_CTL_VGA8 | MGA1064_MISC_CTL_DAC_RAM_CS, + 0x00, 0x00, 0x00) + }; + + size_t i; + + for (i = 0; i < ARRAY_SIZE(dacvalue); i++) { + if ((i <= 0x17) || + (i == 0x1b) || + (i == 0x1c) || + ((i >= 0x1f) && (i <= 0x29)) || + ((i >= 0x30) && (i <= 0x37)) || + ((i >= 0x44) && (i <= 0x4e))) + continue; + WREG_DAC(i, dacvalue[i]); + } + + mgag200_init_registers(mdev); +} + +static void mgag200_g200ev_set_hiprilvl(struct mga_device *mdev) +{ + WREG_ECRT(0x06, 0x00); +} + +/* + * PIXPLLC + */ + +static int mgag200_g200ev_pixpllc_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_state *new_state) +{ + static const unsigned int vcomax = 550000; + static const unsigned int vcomin = 150000; + static const unsigned int pllreffreq = 50000; + + struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); + struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state); + long clock = new_crtc_state->mode.clock; + struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc; + unsigned int delta, tmpdelta; + unsigned int testp, testm, testn; + unsigned int p, m, n, s; + unsigned int computed; + + m = n = p = s = 0; + delta = 0xffffffff; + + for (testp = 16; testp > 0; testp--) { + if (clock * testp > vcomax) + continue; + if (clock * testp < vcomin) + continue; + + for (testn = 1; testn < 257; testn++) { + for (testm = 1; testm < 17; testm++) { + computed = (pllreffreq * testn) / + (testm * testp); + if (computed > clock) + tmpdelta = computed - clock; + else + tmpdelta = clock - computed; + if (tmpdelta < delta) { + delta = tmpdelta; + n = testn; + m = testm; + p = testp; + } + } + } + } + + pixpllc->m = m; + pixpllc->n = n; + pixpllc->p = p; + pixpllc->s = s; + + return 0; +} + +static void mgag200_g200ev_pixpllc_atomic_update(struct drm_crtc *crtc, + struct drm_atomic_state *old_state) +{ + struct drm_device *dev = crtc->dev; + struct mga_device *mdev = to_mga_device(dev); + struct drm_crtc_state *crtc_state = crtc->state; + struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); + struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc; + unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; + u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; + + pixpllcm = pixpllc->m - 1; + pixpllcn = pixpllc->n - 1; + pixpllcp = pixpllc->p - 1; + pixpllcs = pixpllc->s; + + xpixpllcm = pixpllcm; + xpixpllcn = pixpllcn; + xpixpllcp = (pixpllcs << 3) | pixpllcp; + + WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); + + WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); + tmp = RREG8(DAC_DATA); + tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; + WREG8(DAC_DATA, tmp); + + tmp = RREG8(MGAREG_MEM_MISC_READ); + tmp |= 0x3 << 2; + WREG8(MGAREG_MEM_MISC_WRITE, tmp); + + WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT); + tmp = RREG8(DAC_DATA); + WREG8(DAC_DATA, tmp & ~0x40); + + WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); + tmp = RREG8(DAC_DATA); + tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; + WREG8(DAC_DATA, tmp); + + WREG_DAC(MGA1064_EV_PIX_PLLC_M, xpixpllcm); + WREG_DAC(MGA1064_EV_PIX_PLLC_N, xpixpllcn); + WREG_DAC(MGA1064_EV_PIX_PLLC_P, xpixpllcp); + + udelay(50); + + WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); + tmp = RREG8(DAC_DATA); + tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; + WREG8(DAC_DATA, tmp); + + udelay(500); + + WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); + tmp = RREG8(DAC_DATA); + tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; + tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; + WREG8(DAC_DATA, tmp); + + WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT); + tmp = RREG8(DAC_DATA); + WREG8(DAC_DATA, tmp | 0x40); + + tmp = RREG8(MGAREG_MEM_MISC_READ); + tmp |= (0x3 << 2); + WREG8(MGAREG_MEM_MISC_WRITE, tmp); + + WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); + tmp = RREG8(DAC_DATA); + tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; + WREG8(DAC_DATA, tmp); +} + +/* + * Mode-setting pipeline + */ + +static const struct drm_plane_helper_funcs mgag200_g200ev_primary_plane_helper_funcs = { + MGAG200_PRIMARY_PLANE_HELPER_FUNCS, +}; + +static const struct drm_plane_funcs mgag200_g200ev_primary_plane_funcs = { + MGAG200_PRIMARY_PLANE_FUNCS, +}; + +static void mgag200_g200ev_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_state *old_state) +{ + struct drm_device *dev = crtc->dev; + struct mga_device *mdev = to_mga_device(dev); + const struct mgag200_device_funcs *funcs = mdev->funcs; + struct drm_crtc_state *crtc_state = crtc->state; + struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; + struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); + const struct drm_format_info *format = mgag200_crtc_state->format; + + if (funcs->disable_vidrst) + funcs->disable_vidrst(mdev); + + mgag200_set_format_regs(mdev, format); + mgag200_set_mode_regs(mdev, adjusted_mode); + + if (funcs->pixpllc_atomic_update) + funcs->pixpllc_atomic_update(crtc, old_state); + + mgag200_g200ev_set_hiprilvl(mdev); + + mgag200_enable_display(mdev); + + if (funcs->enable_vidrst) + funcs->enable_vidrst(mdev); +} + +static const struct drm_crtc_helper_funcs mgag200_g200ev_crtc_helper_funcs = { + .mode_valid = mgag200_crtc_helper_mode_valid, + .atomic_check = mgag200_crtc_helper_atomic_check, + .atomic_flush = mgag200_crtc_helper_atomic_flush, + .atomic_enable = mgag200_g200ev_crtc_helper_atomic_enable, + .atomic_disable = mgag200_crtc_helper_atomic_disable +}; + +static const struct drm_crtc_funcs mgag200_g200ev_crtc_funcs = { + MGAG200_CRTC_FUNCS, +}; + +static const struct drm_encoder_funcs mgag200_g200ev_dac_encoder_funcs = { + MGAG200_DAC_ENCODER_FUNCS, +}; + +static const struct drm_connector_helper_funcs mgag200_g200ev_vga_connector_helper_funcs = { + MGAG200_VGA_CONNECTOR_HELPER_FUNCS, +}; + +static const struct drm_connector_funcs mgag200_g200ev_vga_connector_funcs = { + MGAG200_VGA_CONNECTOR_FUNCS, +}; + +static int mgag200_g200ev_pipeline_init(struct mga_device *mdev) +{ + struct drm_device *dev = &mdev->base; + struct drm_plane *primary_plane = &mdev->primary_plane; + struct drm_crtc *crtc = &mdev->crtc; + struct drm_encoder *encoder = &mdev->encoder; + struct mga_i2c_chan *i2c = &mdev->i2c; + struct drm_connector *connector = &mdev->connector; + int ret; + + ret = drm_universal_plane_init(dev, primary_plane, 0, + &mgag200_g200ev_primary_plane_funcs, + mgag200_primary_plane_formats, + mgag200_primary_plane_formats_size, + mgag200_primary_plane_fmtmods, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) { + drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret); + return ret; + } + drm_plane_helper_add(primary_plane, &mgag200_g200ev_primary_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(primary_plane); + + ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, + &mgag200_g200ev_crtc_funcs, NULL); + if (ret) { + drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret); + return ret; + } + drm_crtc_helper_add(crtc, &mgag200_g200ev_crtc_helper_funcs); + + /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */ + drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE); + drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE); + + encoder->possible_crtcs = drm_crtc_mask(crtc); + ret = drm_encoder_init(dev, encoder, &mgag200_g200ev_dac_encoder_funcs, + DRM_MODE_ENCODER_DAC, NULL); + if (ret) { + drm_err(dev, "drm_encoder_init() failed: %d\n", ret); + return ret; + } + + ret = mgag200_i2c_init(mdev, i2c); + if (ret) { + drm_err(dev, "failed to add DDC bus: %d\n", ret); + return ret; + } + + ret = drm_connector_init_with_ddc(dev, connector, + &mgag200_g200ev_vga_connector_funcs, + DRM_MODE_CONNECTOR_VGA, + &i2c->adapter); + if (ret) { + drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret); + return ret; + } + drm_connector_helper_add(connector, &mgag200_g200ev_vga_connector_helper_funcs); + + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) { + drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret); + return ret; + } + + return 0; +} + /* * DRM device */ @@ -13,8 +308,12 @@ static const struct mgag200_device_info mgag200_g200ev_device_info = MGAG200_DEVICE_INFO_INIT(2048, 2048, 32700, false, 0, 1, false); -struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type) +static const struct mgag200_device_funcs mgag200_g200ev_device_funcs = { + .pixpllc_atomic_check = mgag200_g200ev_pixpllc_atomic_check, + .pixpllc_atomic_update = mgag200_g200ev_pixpllc_atomic_update, +}; + +struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv) { struct mga_device *mdev; struct drm_device *dev; @@ -36,15 +335,24 @@ struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const stru if (ret) return ERR_PTR(ret); - ret = mgag200_device_init(mdev, type, &mgag200_g200ev_device_info); + ret = mgag200_device_init(mdev, &mgag200_g200ev_device_info, + &mgag200_g200ev_device_funcs); if (ret) return ERR_PTR(ret); + mgag200_g200ev_init_registers(mdev); + vram_available = mgag200_device_probe_vram(mdev); - ret = mgag200_modeset_init(mdev, vram_available); + ret = mgag200_mode_config_init(mdev, vram_available); if (ret) return ERR_PTR(ret); + ret = mgag200_g200ev_pipeline_init(mdev); + if (ret) + return ERR_PTR(ret); + + drm_mode_config_reset(dev); + return mdev; } diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c index 3bfc1324cf78..170934414d7d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c @@ -2,10 +2,179 @@ #include <linux/pci.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> +#include <drm/drm_gem_atomic_helper.h> +#include <drm/drm_probe_helper.h> #include "mgag200_drv.h" +static void mgag200_g200ew3_init_registers(struct mga_device *mdev) +{ + mgag200_g200wb_init_registers(mdev); // same as G200WB + + WREG_ECRT(0x34, 0x5); // G200EW3 specific +} + +/* + * PIXPLLC + */ + +static int mgag200_g200ew3_pixpllc_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_state *new_state) +{ + static const unsigned int vcomax = 800000; + static const unsigned int vcomin = 400000; + static const unsigned int pllreffreq = 25000; + + struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); + struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state); + long clock = new_crtc_state->mode.clock; + struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc; + unsigned int delta, tmpdelta; + unsigned int testp, testm, testn, testp2; + unsigned int p, m, n, s; + unsigned int computed; + + m = n = p = s = 0; + delta = 0xffffffff; + + for (testp = 1; testp < 8; testp++) { + for (testp2 = 1; testp2 < 8; testp2++) { + if (testp < testp2) + continue; + if ((clock * testp * testp2) > vcomax) + continue; + if ((clock * testp * testp2) < vcomin) + continue; + for (testm = 1; testm < 26; testm++) { + for (testn = 32; testn < 2048 ; testn++) { + computed = (pllreffreq * testn) / (testm * testp * testp2); + if (computed > clock) + tmpdelta = computed - clock; + else + tmpdelta = clock - computed; + if (tmpdelta < delta) { + delta = tmpdelta; + m = testm + 1; + n = testn + 1; + p = testp + 1; + s = testp2; + } + } + } + } + } + + pixpllc->m = m; + pixpllc->n = n; + pixpllc->p = p; + pixpllc->s = s; + + return 0; +} + +/* + * Mode-setting pipeline + */ + +static const struct drm_plane_helper_funcs mgag200_g200ew3_primary_plane_helper_funcs = { + MGAG200_PRIMARY_PLANE_HELPER_FUNCS, +}; + +static const struct drm_plane_funcs mgag200_g200ew3_primary_plane_funcs = { + MGAG200_PRIMARY_PLANE_FUNCS, +}; + +static const struct drm_crtc_helper_funcs mgag200_g200ew3_crtc_helper_funcs = { + MGAG200_CRTC_HELPER_FUNCS, +}; + +static const struct drm_crtc_funcs mgag200_g200ew3_crtc_funcs = { + MGAG200_CRTC_FUNCS, +}; + +static const struct drm_encoder_funcs mgag200_g200ew3_dac_encoder_funcs = { + MGAG200_DAC_ENCODER_FUNCS, +}; + +static const struct drm_connector_helper_funcs mgag200_g200ew3_vga_connector_helper_funcs = { + MGAG200_VGA_CONNECTOR_HELPER_FUNCS, +}; + +static const struct drm_connector_funcs mgag200_g200ew3_vga_connector_funcs = { + MGAG200_VGA_CONNECTOR_FUNCS, +}; + +static int mgag200_g200ew3_pipeline_init(struct mga_device *mdev) +{ + struct drm_device *dev = &mdev->base; + struct drm_plane *primary_plane = &mdev->primary_plane; + struct drm_crtc *crtc = &mdev->crtc; + struct drm_encoder *encoder = &mdev->encoder; + struct mga_i2c_chan *i2c = &mdev->i2c; + struct drm_connector *connector = &mdev->connector; + int ret; + + ret = drm_universal_plane_init(dev, primary_plane, 0, + &mgag200_g200ew3_primary_plane_funcs, + mgag200_primary_plane_formats, + mgag200_primary_plane_formats_size, + mgag200_primary_plane_fmtmods, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) { + drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret); + return ret; + } + drm_plane_helper_add(primary_plane, &mgag200_g200ew3_primary_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(primary_plane); + + ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, + &mgag200_g200ew3_crtc_funcs, NULL); + if (ret) { + drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret); + return ret; + } + drm_crtc_helper_add(crtc, &mgag200_g200ew3_crtc_helper_funcs); + + /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */ + drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE); + drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE); + + encoder->possible_crtcs = drm_crtc_mask(crtc); + ret = drm_encoder_init(dev, encoder, &mgag200_g200ew3_dac_encoder_funcs, + DRM_MODE_ENCODER_DAC, NULL); + if (ret) { + drm_err(dev, "drm_encoder_init() failed: %d\n", ret); + return ret; + } + + ret = mgag200_i2c_init(mdev, i2c); + if (ret) { + drm_err(dev, "failed to add DDC bus: %d\n", ret); + return ret; + } + + ret = drm_connector_init_with_ddc(dev, connector, + &mgag200_g200ew3_vga_connector_funcs, + DRM_MODE_CONNECTOR_VGA, + &i2c->adapter); + if (ret) { + drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret); + return ret; + } + drm_connector_helper_add(connector, &mgag200_g200ew3_vga_connector_helper_funcs); + + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) { + drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret); + return ret; + } + + return 0; +} + /* * DRM device */ @@ -13,6 +182,13 @@ static const struct mgag200_device_info mgag200_g200ew3_device_info = MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, true, 0, 1, false); +static const struct mgag200_device_funcs mgag200_g200ew3_device_funcs = { + .disable_vidrst = mgag200_bmc_disable_vidrst, + .enable_vidrst = mgag200_bmc_enable_vidrst, + .pixpllc_atomic_check = mgag200_g200ew3_pixpllc_atomic_check, + .pixpllc_atomic_update = mgag200_g200wb_pixpllc_atomic_update, // same as G200WB +}; + static resource_size_t mgag200_g200ew3_device_probe_vram(struct mga_device *mdev) { resource_size_t vram_size = resource_size(mdev->vram_res); @@ -23,8 +199,7 @@ static resource_size_t mgag200_g200ew3_device_probe_vram(struct mga_device *mdev } struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev, - const struct drm_driver *drv, - enum mga_type type) + const struct drm_driver *drv) { struct mga_device *mdev; struct drm_device *dev; @@ -46,15 +221,24 @@ struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev, if (ret) return ERR_PTR(ret); - ret = mgag200_device_init(mdev, type, &mgag200_g200ew3_device_info); + ret = mgag200_device_init(mdev, &mgag200_g200ew3_device_info, + &mgag200_g200ew3_device_funcs); if (ret) return ERR_PTR(ret); + mgag200_g200ew3_init_registers(mdev); + vram_available = mgag200_g200ew3_device_probe_vram(mdev); - ret = mgag200_modeset_init(mdev, vram_available); + ret = mgag200_mode_config_init(mdev, vram_available); if (ret) return ERR_PTR(ret); + ret = mgag200_g200ew3_pipeline_init(mdev); + if (ret) + return ERR_PTR(ret); + + drm_mode_config_reset(dev); + return mdev; } diff --git a/drivers/gpu/drm/mgag200/mgag200_g200se.c b/drivers/gpu/drm/mgag200/mgag200_g200se.c index 0a3e66695e22..be389ed91cbd 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200se.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200se.c @@ -1,8 +1,13 @@ // SPDX-License-Identifier: GPL-2.0-only +#include <linux/delay.h> #include <linux/pci.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> +#include <drm/drm_gem_atomic_helper.h> +#include <drm/drm_probe_helper.h> #include "mgag200_drv.h" @@ -28,6 +33,404 @@ static int mgag200_g200se_init_pci_options(struct pci_dev *pdev) return mgag200_init_pci_options(pdev, option, 0x00008000); } +static void mgag200_g200se_init_registers(struct mgag200_g200se_device *g200se) +{ + static const u8 dacvalue[] = { + MGAG200_DAC_DEFAULT(0x03, + MGA1064_PIX_CLK_CTL_SEL_PLL, + MGA1064_MISC_CTL_DAC_EN | + MGA1064_MISC_CTL_VGA8 | + MGA1064_MISC_CTL_DAC_RAM_CS, + 0x00, 0x00, 0x00) + }; + + struct mga_device *mdev = &g200se->base; + size_t i; + + for (i = 0; i < ARRAY_SIZE(dacvalue); i++) { + if ((i <= 0x17) || + (i == 0x1b) || + (i == 0x1c) || + ((i >= 0x1f) && (i <= 0x29)) || + ((i == 0x2c) || (i == 0x2d) || (i == 0x2e)) || + ((i >= 0x30) && (i <= 0x37))) + continue; + WREG_DAC(i, dacvalue[i]); + } + + mgag200_init_registers(mdev); +} + +static void mgag200_g200se_set_hiprilvl(struct mga_device *mdev, + const struct drm_display_mode *mode, + const struct drm_format_info *format) +{ + struct mgag200_g200se_device *g200se = to_mgag200_g200se_device(&mdev->base); + unsigned int hiprilvl; + u8 crtcext6; + + if (g200se->unique_rev_id >= 0x04) { + hiprilvl = 0; + } else if (g200se->unique_rev_id >= 0x02) { + unsigned int bpp; + unsigned long mb; + + if (format->cpp[0] * 8 > 16) + bpp = 32; + else if (format->cpp[0] * 8 > 8) + bpp = 16; + else + bpp = 8; + + mb = (mode->clock * bpp) / 1000; + if (mb > 3100) + hiprilvl = 0; + else if (mb > 2600) + hiprilvl = 1; + else if (mb > 1900) + hiprilvl = 2; + else if (mb > 1160) + hiprilvl = 3; + else if (mb > 440) + hiprilvl = 4; + else + hiprilvl = 5; + + } else if (g200se->unique_rev_id >= 0x01) { + hiprilvl = 3; + } else { + hiprilvl = 4; + } + + crtcext6 = hiprilvl; /* implicitly sets maxhipri to 0 */ + + WREG_ECRT(0x06, crtcext6); +} + +/* + * PIXPLLC + */ + +static int mgag200_g200se_00_pixpllc_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_state *new_state) +{ + static const unsigned int vcomax = 320000; + static const unsigned int vcomin = 160000; + static const unsigned int pllreffreq = 25000; + + struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); + struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state); + long clock = new_crtc_state->mode.clock; + struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc; + unsigned int delta, tmpdelta, permitteddelta; + unsigned int testp, testm, testn; + unsigned int p, m, n, s; + unsigned int computed; + + m = n = p = s = 0; + delta = 0xffffffff; + permitteddelta = clock * 5 / 1000; + + for (testp = 8; testp > 0; testp /= 2) { + if (clock * testp > vcomax) + continue; + if (clock * testp < vcomin) + continue; + + for (testn = 17; testn < 256; testn++) { + for (testm = 1; testm < 32; testm++) { + computed = (pllreffreq * testn) / (testm * testp); + if (computed > clock) + tmpdelta = computed - clock; + else + tmpdelta = clock - computed; + if (tmpdelta < delta) { + delta = tmpdelta; + m = testm; + n = testn; + p = testp; + } + } + } + } + + if (delta > permitteddelta) { + pr_warn("PLL delta too large\n"); + return -EINVAL; + } + + pixpllc->m = m; + pixpllc->n = n; + pixpllc->p = p; + pixpllc->s = s; + + return 0; +} + +static void mgag200_g200se_00_pixpllc_atomic_update(struct drm_crtc *crtc, + struct drm_atomic_state *old_state) +{ + struct drm_device *dev = crtc->dev; + struct mga_device *mdev = to_mga_device(dev); + struct drm_crtc_state *crtc_state = crtc->state; + struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); + struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc; + unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; + u8 xpixpllcm, xpixpllcn, xpixpllcp; + + pixpllcm = pixpllc->m - 1; + pixpllcn = pixpllc->n - 1; + pixpllcp = pixpllc->p - 1; + pixpllcs = pixpllc->s; + + xpixpllcm = pixpllcm | ((pixpllcn & BIT(8)) >> 1); + xpixpllcn = pixpllcn; + xpixpllcp = (pixpllcs << 3) | pixpllcp; + + WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); + + WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm); + WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn); + WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp); +} + +static int mgag200_g200se_04_pixpllc_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_state *new_state) +{ + static const unsigned int vcomax = 1600000; + static const unsigned int vcomin = 800000; + static const unsigned int pllreffreq = 25000; + static const unsigned int pvalues_e4[] = {16, 14, 12, 10, 8, 6, 4, 2, 1}; + + struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); + struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state); + long clock = new_crtc_state->mode.clock; + struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc; + unsigned int delta, tmpdelta, permitteddelta; + unsigned int testp, testm, testn; + unsigned int p, m, n, s; + unsigned int computed; + unsigned int fvv; + unsigned int i; + + m = n = p = s = 0; + delta = 0xffffffff; + + if (clock < 25000) + clock = 25000; + clock = clock * 2; + + /* Permited delta is 0.5% as VESA Specification */ + permitteddelta = clock * 5 / 1000; + + for (i = 0 ; i < ARRAY_SIZE(pvalues_e4); i++) { + testp = pvalues_e4[i]; + + if ((clock * testp) > vcomax) + continue; + if ((clock * testp) < vcomin) + continue; + + for (testn = 50; testn <= 256; testn++) { + for (testm = 1; testm <= 32; testm++) { + computed = (pllreffreq * testn) / (testm * testp); + if (computed > clock) + tmpdelta = computed - clock; + else + tmpdelta = clock - computed; + + if (tmpdelta < delta) { + delta = tmpdelta; + m = testm; + n = testn; + p = testp; + } + } + } + } + + fvv = pllreffreq * n / m; + fvv = (fvv - 800000) / 50000; + if (fvv > 15) + fvv = 15; + s = fvv << 1; + + if (delta > permitteddelta) { + pr_warn("PLL delta too large\n"); + return -EINVAL; + } + + pixpllc->m = m; + pixpllc->n = n; + pixpllc->p = p; + pixpllc->s = s; + + return 0; +} + +static void mgag200_g200se_04_pixpllc_atomic_update(struct drm_crtc *crtc, + struct drm_atomic_state *old_state) +{ + struct drm_device *dev = crtc->dev; + struct mga_device *mdev = to_mga_device(dev); + struct drm_crtc_state *crtc_state = crtc->state; + struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); + struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc; + unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; + u8 xpixpllcm, xpixpllcn, xpixpllcp; + + pixpllcm = pixpllc->m - 1; + pixpllcn = pixpllc->n - 1; + pixpllcp = pixpllc->p - 1; + pixpllcs = pixpllc->s; + + xpixpllcm = pixpllcm | ((pixpllcn & BIT(8)) >> 1); + xpixpllcn = pixpllcn; + xpixpllcp = (pixpllcs << 3) | pixpllcp; + + WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); + + WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm); + WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn); + WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp); + + WREG_DAC(0x1a, 0x09); + msleep(20); + WREG_DAC(0x1a, 0x01); +} + +/* + * Mode-setting pipeline + */ + +static const struct drm_plane_helper_funcs mgag200_g200se_primary_plane_helper_funcs = { + MGAG200_PRIMARY_PLANE_HELPER_FUNCS, +}; + +static const struct drm_plane_funcs mgag200_g200se_primary_plane_funcs = { + MGAG200_PRIMARY_PLANE_FUNCS, +}; + +static void mgag200_g200se_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_state *old_state) +{ + struct drm_device *dev = crtc->dev; + struct mga_device *mdev = to_mga_device(dev); + const struct mgag200_device_funcs *funcs = mdev->funcs; + struct drm_crtc_state *crtc_state = crtc->state; + struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; + struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); + const struct drm_format_info *format = mgag200_crtc_state->format; + + if (funcs->disable_vidrst) + funcs->disable_vidrst(mdev); + + mgag200_set_format_regs(mdev, format); + mgag200_set_mode_regs(mdev, adjusted_mode); + + if (funcs->pixpllc_atomic_update) + funcs->pixpllc_atomic_update(crtc, old_state); + + mgag200_g200se_set_hiprilvl(mdev, adjusted_mode, format); + + mgag200_enable_display(mdev); + + if (funcs->enable_vidrst) + funcs->enable_vidrst(mdev); +} + +static const struct drm_crtc_helper_funcs mgag200_g200se_crtc_helper_funcs = { + .mode_valid = mgag200_crtc_helper_mode_valid, + .atomic_check = mgag200_crtc_helper_atomic_check, + .atomic_flush = mgag200_crtc_helper_atomic_flush, + .atomic_enable = mgag200_g200se_crtc_helper_atomic_enable, + .atomic_disable = mgag200_crtc_helper_atomic_disable +}; + +static const struct drm_crtc_funcs mgag200_g200se_crtc_funcs = { + MGAG200_CRTC_FUNCS, +}; + +static const struct drm_encoder_funcs mgag200_g200se_dac_encoder_funcs = { + MGAG200_DAC_ENCODER_FUNCS, +}; + +static const struct drm_connector_helper_funcs mgag200_g200se_vga_connector_helper_funcs = { + MGAG200_VGA_CONNECTOR_HELPER_FUNCS, +}; + +static const struct drm_connector_funcs mgag200_g200se_vga_connector_funcs = { + MGAG200_VGA_CONNECTOR_FUNCS, +}; + +static int mgag200_g200se_pipeline_init(struct mga_device *mdev) +{ + struct drm_device *dev = &mdev->base; + struct drm_plane *primary_plane = &mdev->primary_plane; + struct drm_crtc *crtc = &mdev->crtc; + struct drm_encoder *encoder = &mdev->encoder; + struct mga_i2c_chan *i2c = &mdev->i2c; + struct drm_connector *connector = &mdev->connector; + int ret; + + ret = drm_universal_plane_init(dev, primary_plane, 0, + &mgag200_g200se_primary_plane_funcs, + mgag200_primary_plane_formats, + mgag200_primary_plane_formats_size, + mgag200_primary_plane_fmtmods, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) { + drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret); + return ret; + } + drm_plane_helper_add(primary_plane, &mgag200_g200se_primary_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(primary_plane); + + ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, + &mgag200_g200se_crtc_funcs, NULL); + if (ret) { + drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret); + return ret; + } + drm_crtc_helper_add(crtc, &mgag200_g200se_crtc_helper_funcs); + + /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */ + drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE); + drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE); + + encoder->possible_crtcs = drm_crtc_mask(crtc); + ret = drm_encoder_init(dev, encoder, &mgag200_g200se_dac_encoder_funcs, + DRM_MODE_ENCODER_DAC, NULL); + if (ret) { + drm_err(dev, "drm_encoder_init() failed: %d\n", ret); + return ret; + } + + ret = mgag200_i2c_init(mdev, i2c); + if (ret) { + drm_err(dev, "failed to add DDC bus: %d\n", ret); + return ret; + } + + ret = drm_connector_init_with_ddc(dev, connector, + &mgag200_g200se_vga_connector_funcs, + DRM_MODE_CONNECTOR_VGA, + &i2c->adapter); + if (ret) { + drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret); + return ret; + } + drm_connector_helper_add(connector, &mgag200_g200se_vga_connector_helper_funcs); + + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) { + drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret); + return ret; + } + + return 0; +} + /* * DRM device */ @@ -65,11 +468,22 @@ static int mgag200_g200se_init_unique_rev_id(struct mgag200_g200se_device *g200s return 0; } +static const struct mgag200_device_funcs mgag200_g200se_00_device_funcs = { + .pixpllc_atomic_check = mgag200_g200se_00_pixpllc_atomic_check, + .pixpllc_atomic_update = mgag200_g200se_00_pixpllc_atomic_update, +}; + +static const struct mgag200_device_funcs mgag200_g200se_04_device_funcs = { + .pixpllc_atomic_check = mgag200_g200se_04_pixpllc_atomic_check, + .pixpllc_atomic_update = mgag200_g200se_04_pixpllc_atomic_update, +}; + struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const struct drm_driver *drv, enum mga_type type) { struct mgag200_g200se_device *g200se; const struct mgag200_device_info *info; + const struct mgag200_device_funcs *funcs; struct mga_device *mdev; struct drm_device *dev; resource_size_t vram_available; @@ -116,15 +530,28 @@ struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const stru return ERR_PTR(-EINVAL); } - ret = mgag200_device_init(mdev, type, info); + if (g200se->unique_rev_id >= 0x04) + funcs = &mgag200_g200se_04_device_funcs; + else + funcs = &mgag200_g200se_00_device_funcs; + + ret = mgag200_device_init(mdev, info, funcs); if (ret) return ERR_PTR(ret); + mgag200_g200se_init_registers(g200se); + vram_available = mgag200_device_probe_vram(mdev); - ret = mgag200_modeset_init(mdev, vram_available); + ret = mgag200_mode_config_init(mdev, vram_available); if (ret) return ERR_PTR(ret); + ret = mgag200_g200se_pipeline_init(mdev); + if (ret) + return ERR_PTR(ret); + + drm_mode_config_reset(dev); + return mdev; } diff --git a/drivers/gpu/drm/mgag200/mgag200_g200wb.c b/drivers/gpu/drm/mgag200/mgag200_g200wb.c index c8450ac8eaec..9baa727ac6f9 100644 --- a/drivers/gpu/drm/mgag200/mgag200_g200wb.c +++ b/drivers/gpu/drm/mgag200/mgag200_g200wb.c @@ -1,11 +1,314 @@ // SPDX-License-Identifier: GPL-2.0-only +#include <linux/delay.h> #include <linux/pci.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> +#include <drm/drm_gem_atomic_helper.h> +#include <drm/drm_probe_helper.h> #include "mgag200_drv.h" +void mgag200_g200wb_init_registers(struct mga_device *mdev) +{ + static const u8 dacvalue[] = { + MGAG200_DAC_DEFAULT(0x07, 0xc9, 0x1f, 0x00, 0x00, 0x00) + }; + + size_t i; + + for (i = 0; i < ARRAY_SIZE(dacvalue); i++) { + if ((i <= 0x17) || + (i == 0x1b) || + (i == 0x1c) || + ((i >= 0x1f) && (i <= 0x29)) || + ((i >= 0x30) && (i <= 0x37)) || + ((i >= 0x44) && (i <= 0x4e))) + continue; + WREG_DAC(i, dacvalue[i]); + } + + mgag200_init_registers(mdev); +} + +/* + * PIXPLLC + */ + +static int mgag200_g200wb_pixpllc_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_state *new_state) +{ + static const unsigned int vcomax = 550000; + static const unsigned int vcomin = 150000; + static const unsigned int pllreffreq = 48000; + + struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); + struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state); + long clock = new_crtc_state->mode.clock; + struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc; + unsigned int delta, tmpdelta; + unsigned int testp, testm, testn; + unsigned int p, m, n, s; + unsigned int computed; + + m = n = p = s = 0; + delta = 0xffffffff; + + for (testp = 1; testp < 9; testp++) { + if (clock * testp > vcomax) + continue; + if (clock * testp < vcomin) + continue; + + for (testm = 1; testm < 17; testm++) { + for (testn = 1; testn < 151; testn++) { + computed = (pllreffreq * testn) / (testm * testp); + if (computed > clock) + tmpdelta = computed - clock; + else + tmpdelta = clock - computed; + if (tmpdelta < delta) { + delta = tmpdelta; + n = testn; + m = testm; + p = testp; + s = 0; + } + } + } + } + + pixpllc->m = m; + pixpllc->n = n; + pixpllc->p = p; + pixpllc->s = s; + + return 0; +} + +void mgag200_g200wb_pixpllc_atomic_update(struct drm_crtc *crtc, + struct drm_atomic_state *old_state) +{ + struct drm_device *dev = crtc->dev; + struct mga_device *mdev = to_mga_device(dev); + struct drm_crtc_state *crtc_state = crtc->state; + struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); + struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc; + bool pll_locked = false; + unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; + u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; + int i, j, tmpcount, vcount; + + pixpllcm = pixpllc->m - 1; + pixpllcn = pixpllc->n - 1; + pixpllcp = pixpllc->p - 1; + pixpllcs = pixpllc->s; + + xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm; + xpixpllcn = pixpllcn; + xpixpllcp = ((pixpllcn & GENMASK(10, 9)) >> 3) | (pixpllcs << 3) | pixpllcp; + + WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); + + for (i = 0; i <= 32 && pll_locked == false; i++) { + if (i > 0) { + WREG8(MGAREG_CRTC_INDEX, 0x1e); + tmp = RREG8(MGAREG_CRTC_DATA); + if (tmp < 0xff) + WREG8(MGAREG_CRTC_DATA, tmp+1); + } + + /* set pixclkdis to 1 */ + WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); + tmp = RREG8(DAC_DATA); + tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; + WREG8(DAC_DATA, tmp); + + WREG8(DAC_INDEX, MGA1064_REMHEADCTL); + tmp = RREG8(DAC_DATA); + tmp |= MGA1064_REMHEADCTL_CLKDIS; + WREG8(DAC_DATA, tmp); + + /* select PLL Set C */ + tmp = RREG8(MGAREG_MEM_MISC_READ); + tmp |= 0x3 << 2; + WREG8(MGAREG_MEM_MISC_WRITE, tmp); + + WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); + tmp = RREG8(DAC_DATA); + tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN | 0x80; + WREG8(DAC_DATA, tmp); + + udelay(500); + + /* reset the PLL */ + WREG8(DAC_INDEX, MGA1064_VREF_CTL); + tmp = RREG8(DAC_DATA); + tmp &= ~0x04; + WREG8(DAC_DATA, tmp); + + udelay(50); + + /* program pixel pll register */ + WREG_DAC(MGA1064_WB_PIX_PLLC_N, xpixpllcn); + WREG_DAC(MGA1064_WB_PIX_PLLC_M, xpixpllcm); + WREG_DAC(MGA1064_WB_PIX_PLLC_P, xpixpllcp); + + udelay(50); + + /* turn pll on */ + WREG8(DAC_INDEX, MGA1064_VREF_CTL); + tmp = RREG8(DAC_DATA); + tmp |= 0x04; + WREG_DAC(MGA1064_VREF_CTL, tmp); + + udelay(500); + + /* select the pixel pll */ + WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); + tmp = RREG8(DAC_DATA); + tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; + tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; + WREG8(DAC_DATA, tmp); + + WREG8(DAC_INDEX, MGA1064_REMHEADCTL); + tmp = RREG8(DAC_DATA); + tmp &= ~MGA1064_REMHEADCTL_CLKSL_MSK; + tmp |= MGA1064_REMHEADCTL_CLKSL_PLL; + WREG8(DAC_DATA, tmp); + + /* reset dotclock rate bit */ + WREG8(MGAREG_SEQ_INDEX, 1); + tmp = RREG8(MGAREG_SEQ_DATA); + tmp &= ~0x8; + WREG8(MGAREG_SEQ_DATA, tmp); + + WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); + tmp = RREG8(DAC_DATA); + tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; + WREG8(DAC_DATA, tmp); + + vcount = RREG8(MGAREG_VCOUNT); + + for (j = 0; j < 30 && pll_locked == false; j++) { + tmpcount = RREG8(MGAREG_VCOUNT); + if (tmpcount < vcount) + vcount = 0; + if ((tmpcount - vcount) > 2) + pll_locked = true; + else + udelay(5); + } + } + + WREG8(DAC_INDEX, MGA1064_REMHEADCTL); + tmp = RREG8(DAC_DATA); + tmp &= ~MGA1064_REMHEADCTL_CLKDIS; + WREG_DAC(MGA1064_REMHEADCTL, tmp); +} + +/* + * Mode-setting pipeline + */ + +static const struct drm_plane_helper_funcs mgag200_g200wb_primary_plane_helper_funcs = { + MGAG200_PRIMARY_PLANE_HELPER_FUNCS, +}; + +static const struct drm_plane_funcs mgag200_g200wb_primary_plane_funcs = { + MGAG200_PRIMARY_PLANE_FUNCS, +}; + +static const struct drm_crtc_helper_funcs mgag200_g200wb_crtc_helper_funcs = { + MGAG200_CRTC_HELPER_FUNCS, +}; + +static const struct drm_crtc_funcs mgag200_g200wb_crtc_funcs = { + MGAG200_CRTC_FUNCS, +}; + +static const struct drm_encoder_funcs mgag200_g200wb_dac_encoder_funcs = { + MGAG200_DAC_ENCODER_FUNCS, +}; + +static const struct drm_connector_helper_funcs mgag200_g200wb_vga_connector_helper_funcs = { + MGAG200_VGA_CONNECTOR_HELPER_FUNCS, +}; + +static const struct drm_connector_funcs mgag200_g200wb_vga_connector_funcs = { + MGAG200_VGA_CONNECTOR_FUNCS, +}; + +static int mgag200_g200wb_pipeline_init(struct mga_device *mdev) +{ + struct drm_device *dev = &mdev->base; + struct drm_plane *primary_plane = &mdev->primary_plane; + struct drm_crtc *crtc = &mdev->crtc; + struct drm_encoder *encoder = &mdev->encoder; + struct mga_i2c_chan *i2c = &mdev->i2c; + struct drm_connector *connector = &mdev->connector; + int ret; + + ret = drm_universal_plane_init(dev, primary_plane, 0, + &mgag200_g200wb_primary_plane_funcs, + mgag200_primary_plane_formats, + mgag200_primary_plane_formats_size, + mgag200_primary_plane_fmtmods, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) { + drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret); + return ret; + } + drm_plane_helper_add(primary_plane, &mgag200_g200wb_primary_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(primary_plane); + + ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, + &mgag200_g200wb_crtc_funcs, NULL); + if (ret) { + drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret); + return ret; + } + drm_crtc_helper_add(crtc, &mgag200_g200wb_crtc_helper_funcs); + + /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */ + drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE); + drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE); + + encoder->possible_crtcs = drm_crtc_mask(crtc); + ret = drm_encoder_init(dev, encoder, &mgag200_g200wb_dac_encoder_funcs, + DRM_MODE_ENCODER_DAC, NULL); + if (ret) { + drm_err(dev, "drm_encoder_init() failed: %d\n", ret); + return ret; + } + + ret = mgag200_i2c_init(mdev, i2c); + if (ret) { + drm_err(dev, "failed to add DDC bus: %d\n", ret); + return ret; + } + + ret = drm_connector_init_with_ddc(dev, connector, + &mgag200_g200wb_vga_connector_funcs, + DRM_MODE_CONNECTOR_VGA, + &i2c->adapter); + if (ret) { + drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret); + return ret; + } + drm_connector_helper_add(connector, &mgag200_g200wb_vga_connector_helper_funcs); + + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) { + drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret); + return ret; + } + + return 0; +} + /* * DRM device */ @@ -13,8 +316,14 @@ static const struct mgag200_device_info mgag200_g200wb_device_info = MGAG200_DEVICE_INFO_INIT(1280, 1024, 31877, true, 0, 1, false); -struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv, - enum mga_type type) +static const struct mgag200_device_funcs mgag200_g200wb_device_funcs = { + .disable_vidrst = mgag200_bmc_disable_vidrst, + .enable_vidrst = mgag200_bmc_enable_vidrst, + .pixpllc_atomic_check = mgag200_g200wb_pixpllc_atomic_check, + .pixpllc_atomic_update = mgag200_g200wb_pixpllc_atomic_update, +}; + +struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv) { struct mga_device *mdev; struct drm_device *dev; @@ -36,15 +345,24 @@ struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const stru if (ret) return ERR_PTR(ret); - ret = mgag200_device_init(mdev, type, &mgag200_g200wb_device_info); + ret = mgag200_device_init(mdev, &mgag200_g200wb_device_info, + &mgag200_g200wb_device_funcs); if (ret) return ERR_PTR(ret); + mgag200_g200wb_init_registers(mdev); + vram_available = mgag200_device_probe_vram(mdev); - ret = mgag200_modeset_init(mdev, vram_available); + ret = mgag200_mode_config_init(mdev, vram_available); if (ret) return ERR_PTR(ret); + ret = mgag200_g200wb_pipeline_init(mdev); + if (ret) + return ERR_PTR(ret); + + drm_mode_config_reset(dev); + return mdev; } diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 225cca2ed60e..bbab2549243a 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -11,24 +11,19 @@ #include <linux/delay.h> #include <linux/iosys-map.h> +#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> -#include <drm/drm_atomic_state_helper.h> -#include <drm/drm_crtc_helper.h> #include <drm/drm_damage_helper.h> #include <drm/drm_format_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_framebuffer_helper.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> -#include <drm/drm_simple_kms_helper.h> #include "mgag200_drv.h" -#define MGAG200_LUT_SIZE 256 - /* * This file contains setup code for the CRTC. */ @@ -132,95 +127,6 @@ static inline void mga_wait_busy(struct mga_device *mdev) } while ((status & 0x01) && time_before(jiffies, timeout)); } -static void mgag200_g200wb_hold_bmc(struct mga_device *mdev) -{ - u8 tmp; - int iter_max; - - /* 1- The first step is to warn the BMC of an upcoming mode change. - * We are putting the misc<0> to output.*/ - - WREG8(DAC_INDEX, MGA1064_GEN_IO_CTL); - tmp = RREG8(DAC_DATA); - tmp |= 0x10; - WREG_DAC(MGA1064_GEN_IO_CTL, tmp); - - /* we are putting a 1 on the misc<0> line */ - WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA); - tmp = RREG8(DAC_DATA); - tmp |= 0x10; - WREG_DAC(MGA1064_GEN_IO_DATA, tmp); - - /* 2- Second step to mask and further scan request - * This will be done by asserting the remfreqmsk bit (XSPAREREG<7>) - */ - WREG8(DAC_INDEX, MGA1064_SPAREREG); - tmp = RREG8(DAC_DATA); - tmp |= 0x80; - WREG_DAC(MGA1064_SPAREREG, tmp); - - /* 3a- the third step is to verifu if there is an active scan - * We are searching for a 0 on remhsyncsts <XSPAREREG<0>) - */ - iter_max = 300; - while (!(tmp & 0x1) && iter_max) { - WREG8(DAC_INDEX, MGA1064_SPAREREG); - tmp = RREG8(DAC_DATA); - udelay(1000); - iter_max--; - } - - /* 3b- this step occurs only if the remove is actually scanning - * we are waiting for the end of the frame which is a 1 on - * remvsyncsts (XSPAREREG<1>) - */ - if (iter_max) { - iter_max = 300; - while ((tmp & 0x2) && iter_max) { - WREG8(DAC_INDEX, MGA1064_SPAREREG); - tmp = RREG8(DAC_DATA); - udelay(1000); - iter_max--; - } - } -} - -static void mgag200_g200wb_release_bmc(struct mga_device *mdev) -{ - u8 tmp; - - /* 1- The first step is to ensure that the vrsten and hrsten are set */ - WREG8(MGAREG_CRTCEXT_INDEX, 1); - tmp = RREG8(MGAREG_CRTCEXT_DATA); - WREG8(MGAREG_CRTCEXT_DATA, tmp | 0x88); - - /* 2- second step is to assert the rstlvl2 */ - WREG8(DAC_INDEX, MGA1064_REMHEADCTL2); - tmp = RREG8(DAC_DATA); - tmp |= 0x8; - WREG8(DAC_DATA, tmp); - - /* wait 10 us */ - udelay(10); - - /* 3- deassert rstlvl2 */ - tmp &= ~0x08; - WREG8(DAC_INDEX, MGA1064_REMHEADCTL2); - WREG8(DAC_DATA, tmp); - - /* 4- remove mask of scan request */ - WREG8(DAC_INDEX, MGA1064_SPAREREG); - tmp = RREG8(DAC_DATA); - tmp &= ~0x80; - WREG8(DAC_DATA, tmp); - - /* 5- put back a 0 on the misc<0> line */ - WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA); - tmp = RREG8(DAC_DATA); - tmp &= ~0x10; - WREG_DAC(MGA1064_GEN_IO_DATA, tmp); -} - /* * This is how the framebuffer base address is stored in g200 cards: * * Assume @offset is the gpu_addr variable of the framebuffer object @@ -267,86 +173,10 @@ static void mgag200_set_startadd(struct mga_device *mdev, WREG_ECRT(0x00, crtcext0); } -static void mgag200_set_dac_regs(struct mga_device *mdev) -{ - size_t i; - u8 dacvalue[] = { - /* 0x00: */ 0, 0, 0, 0, 0, 0, 0x00, 0, - /* 0x08: */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x10: */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x18: */ 0x00, 0, 0xC9, 0xFF, 0xBF, 0x20, 0x1F, 0x20, - /* 0x20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x28: */ 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x40, - /* 0x30: */ 0x00, 0xB0, 0x00, 0xC2, 0x34, 0x14, 0x02, 0x83, - /* 0x38: */ 0x00, 0x93, 0x00, 0x77, 0x00, 0x00, 0x00, 0x3A, - /* 0x40: */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x48: */ 0, 0, 0, 0, 0, 0, 0, 0 - }; - - switch (mdev->type) { - case G200_PCI: - case G200_AGP: - dacvalue[MGA1064_SYS_PLL_M] = 0x04; - dacvalue[MGA1064_SYS_PLL_N] = 0x2D; - dacvalue[MGA1064_SYS_PLL_P] = 0x19; - break; - case G200_SE_A: - case G200_SE_B: - dacvalue[MGA1064_VREF_CTL] = 0x03; - dacvalue[MGA1064_PIX_CLK_CTL] = MGA1064_PIX_CLK_CTL_SEL_PLL; - dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_DAC_EN | - MGA1064_MISC_CTL_VGA8 | - MGA1064_MISC_CTL_DAC_RAM_CS; - break; - case G200_WB: - case G200_EW3: - dacvalue[MGA1064_VREF_CTL] = 0x07; - break; - case G200_EV: - dacvalue[MGA1064_PIX_CLK_CTL] = MGA1064_PIX_CLK_CTL_SEL_PLL; - dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 | - MGA1064_MISC_CTL_DAC_RAM_CS; - break; - case G200_EH: - case G200_EH3: - dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 | - MGA1064_MISC_CTL_DAC_RAM_CS; - break; - case G200_ER: - break; - } - - for (i = 0; i < ARRAY_SIZE(dacvalue); i++) { - if ((i <= 0x17) || - (i == 0x1b) || - (i == 0x1c) || - ((i >= 0x1f) && (i <= 0x29)) || - ((i >= 0x30) && (i <= 0x37))) - continue; - if (IS_G200_SE(mdev) && - ((i == 0x2c) || (i == 0x2d) || (i == 0x2e))) - continue; - if ((mdev->type == G200_EV || - mdev->type == G200_WB || - mdev->type == G200_EH || - mdev->type == G200_EW3 || - mdev->type == G200_EH3) && - (i >= 0x44) && (i <= 0x4e)) - continue; - - WREG_DAC(i, dacvalue[i]); - } - - if (mdev->type == G200_ER) - WREG_DAC(0x90, 0); -} - -static void mgag200_init_regs(struct mga_device *mdev) +void mgag200_init_registers(struct mga_device *mdev) { u8 crtc11, misc; - mgag200_set_dac_regs(mdev); - WREG_SEQ(2, 0x0f); WREG_SEQ(3, 0x00); WREG_SEQ(4, 0x0e); @@ -364,19 +194,12 @@ static void mgag200_init_regs(struct mga_device *mdev) MGAREG_CRTC11_VINTCLR); WREG_CRT(0x11, crtc11); - if (mdev->type == G200_ER) - WREG_ECRT(0x24, 0x5); - - if (mdev->type == G200_EW3) - WREG_ECRT(0x34, 0x5); - misc = RREG8(MGA_MISC_IN); misc |= MGAREG_MISC_IOADSEL; WREG8(MGA_MISC_OUT, misc); } -static void mgag200_set_mode_regs(struct mga_device *mdev, - const struct drm_display_mode *mode) +void mgag200_set_mode_regs(struct mga_device *mdev, const struct drm_display_mode *mode) { const struct mgag200_device_info *info = mdev->info; unsigned int hdisplay, hsyncstart, hsyncend, htotal; @@ -500,11 +323,9 @@ static void mgag200_set_offset(struct mga_device *mdev, WREG_ECRT(0x00, crtcext0); } -static void mgag200_set_format_regs(struct mga_device *mdev, - const struct drm_framebuffer *fb) +void mgag200_set_format_regs(struct mga_device *mdev, const struct drm_format_info *format) { struct drm_device *dev = &mdev->base; - const struct drm_format_info *format = fb->format; unsigned int bpp, bppshift, scale; u8 crtcext3, xmulctrl; @@ -565,76 +386,9 @@ static void mgag200_set_format_regs(struct mga_device *mdev, WREG_ECRT(3, crtcext3); } -static void mgag200_g200er_reset_tagfifo(struct mga_device *mdev) +void mgag200_enable_display(struct mga_device *mdev) { - static uint32_t RESET_FLAG = 0x00200000; /* undocumented magic value */ - u32 memctl; - - memctl = RREG32(MGAREG_MEMCTL); - - memctl |= RESET_FLAG; - WREG32(MGAREG_MEMCTL, memctl); - - udelay(1000); - - memctl &= ~RESET_FLAG; - WREG32(MGAREG_MEMCTL, memctl); -} - -static void mgag200_g200se_set_hiprilvl(struct mga_device *mdev, - const struct drm_display_mode *mode, - const struct drm_framebuffer *fb) -{ - struct mgag200_g200se_device *g200se = to_mgag200_g200se_device(&mdev->base); - unsigned int hiprilvl; - u8 crtcext6; - - if (g200se->unique_rev_id >= 0x04) { - hiprilvl = 0; - } else if (g200se->unique_rev_id >= 0x02) { - unsigned int bpp; - unsigned long mb; - - if (fb->format->cpp[0] * 8 > 16) - bpp = 32; - else if (fb->format->cpp[0] * 8 > 8) - bpp = 16; - else - bpp = 8; - - mb = (mode->clock * bpp) / 1000; - if (mb > 3100) - hiprilvl = 0; - else if (mb > 2600) - hiprilvl = 1; - else if (mb > 1900) - hiprilvl = 2; - else if (mb > 1160) - hiprilvl = 3; - else if (mb > 440) - hiprilvl = 4; - else - hiprilvl = 5; - - } else if (g200se->unique_rev_id >= 0x01) { - hiprilvl = 3; - } else { - hiprilvl = 4; - } - - crtcext6 = hiprilvl; /* implicitly sets maxhipri to 0 */ - - WREG_ECRT(0x06, crtcext6); -} - -static void mgag200_g200ev_set_hiprilvl(struct mga_device *mdev) -{ - WREG_ECRT(0x06, 0x00); -} - -static void mgag200_enable_display(struct mga_device *mdev) -{ - u8 seq0, seq1, crtcext1; + u8 seq0, crtcext1; RREG_SEQ(0x00, seq0); seq0 |= MGAREG_SEQ0_SYNCRST | @@ -648,12 +402,6 @@ static void mgag200_enable_display(struct mga_device *mdev) mga_wait_vsync(mdev); mga_wait_busy(mdev); - RREG_SEQ(0x01, seq1); - seq1 &= ~MGAREG_SEQ1_SCROFF; - WREG_SEQ(0x01, seq1); - - msleep(20); - RREG_ECRT(0x01, crtcext1); crtcext1 &= ~MGAREG_CRTCEXT1_VSYNCOFF; crtcext1 &= ~MGAREG_CRTCEXT1_HSYNCOFF; @@ -662,7 +410,7 @@ static void mgag200_enable_display(struct mga_device *mdev) static void mgag200_disable_display(struct mga_device *mdev) { - u8 seq0, seq1, crtcext1; + u8 seq0, crtcext1; RREG_SEQ(0x00, seq0); seq0 &= ~MGAREG_SEQ0_SYNCRST; @@ -675,59 +423,127 @@ static void mgag200_disable_display(struct mga_device *mdev) mga_wait_vsync(mdev); mga_wait_busy(mdev); - RREG_SEQ(0x01, seq1); - seq1 |= MGAREG_SEQ1_SCROFF; - WREG_SEQ(0x01, seq1); - - msleep(20); - RREG_ECRT(0x01, crtcext1); crtcext1 |= MGAREG_CRTCEXT1_VSYNCOFF | MGAREG_CRTCEXT1_HSYNCOFF; WREG_ECRT(0x01, crtcext1); } +static void mgag200_handle_damage(struct mga_device *mdev, const struct iosys_map *vmap, + struct drm_framebuffer *fb, struct drm_rect *clip) +{ + struct iosys_map dst = IOSYS_MAP_INIT_VADDR_IOMEM(mdev->vram); + + iosys_map_incr(&dst, drm_fb_clip_offset(fb->pitches[0], fb->format, clip)); + drm_fb_memcpy(&dst, fb->pitches, vmap, fb, clip); +} + /* - * Connector + * Primary plane */ -static int mgag200_vga_connector_helper_get_modes(struct drm_connector *connector) +const uint32_t mgag200_primary_plane_formats[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_RGB565, + DRM_FORMAT_RGB888, +}; + +const size_t mgag200_primary_plane_formats_size = ARRAY_SIZE(mgag200_primary_plane_formats); + +const uint64_t mgag200_primary_plane_fmtmods[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + +int mgag200_primary_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_atomic_state *new_state) { - struct mga_device *mdev = to_mga_device(connector->dev); + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane); + struct drm_framebuffer *new_fb = new_plane_state->fb; + struct drm_framebuffer *fb = NULL; + struct drm_crtc *new_crtc = new_plane_state->crtc; + struct drm_crtc_state *new_crtc_state = NULL; + struct mgag200_crtc_state *new_mgag200_crtc_state; int ret; - /* - * Protect access to I/O registers from concurrent modesetting - * by acquiring the I/O-register lock. - */ - mutex_lock(&mdev->rmmio_lock); - ret = drm_connector_helper_get_modes_from_ddc(connector); - mutex_unlock(&mdev->rmmio_lock); + if (new_crtc) + new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_crtc); - return ret; + ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, true); + if (ret) + return ret; + else if (!new_plane_state->visible) + return 0; + + if (plane->state) + fb = plane->state->fb; + + if (!fb || (fb->format != new_fb->format)) + new_crtc_state->mode_changed = true; /* update PLL settings */ + + new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state); + new_mgag200_crtc_state->format = new_fb->format; + + return 0; } -static const struct drm_connector_helper_funcs mga_vga_connector_helper_funcs = { - .get_modes = mgag200_vga_connector_helper_get_modes, -}; +void mgag200_primary_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_state *old_state) +{ + struct drm_device *dev = plane->dev; + struct mga_device *mdev = to_mga_device(dev); + struct drm_plane_state *plane_state = plane->state; + struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(old_state, plane); + struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); + struct drm_framebuffer *fb = plane_state->fb; + struct drm_atomic_helper_damage_iter iter; + struct drm_rect damage; + u8 seq1; -static const struct drm_connector_funcs mga_vga_connector_funcs = { - .reset = drm_atomic_helper_connector_reset, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = drm_connector_cleanup, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; + if (!fb) + return; + + drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); + drm_atomic_for_each_plane_damage(&iter, &damage) { + mgag200_handle_damage(mdev, shadow_plane_state->data, fb, &damage); + } + + /* Always scanout image at VRAM offset 0 */ + mgag200_set_startadd(mdev, (u32)0); + mgag200_set_offset(mdev, fb); + + if (!old_plane_state->crtc && plane_state->crtc) { // enabling + RREG_SEQ(0x01, seq1); + seq1 &= ~MGAREG_SEQ1_SCROFF; + WREG_SEQ(0x01, seq1); + msleep(20); + } +} + +void mgag200_primary_plane_helper_atomic_disable(struct drm_plane *plane, + struct drm_atomic_state *old_state) +{ + struct drm_device *dev = plane->dev; + struct mga_device *mdev = to_mga_device(dev); + u8 seq1; + + RREG_SEQ(0x01, seq1); + seq1 |= MGAREG_SEQ1_SCROFF; + WREG_SEQ(0x01, seq1); + msleep(20); +} /* - * Simple Display Pipe + * CRTC */ -static enum drm_mode_status -mgag200_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe, - const struct drm_display_mode *mode) +enum drm_mode_status mgag200_crtc_helper_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) { - struct mga_device *mdev = to_mga_device(pipe->crtc.dev); + struct mga_device *mdev = to_mga_device(crtc->dev); const struct mgag200_device_info *info = mdev->info; /* @@ -754,167 +570,112 @@ mgag200_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe, return MODE_OK; } -static void -mgag200_handle_damage(struct mga_device *mdev, struct drm_framebuffer *fb, - struct drm_rect *clip, const struct iosys_map *map) -{ - void __iomem *dst = mdev->vram; - void *vmap = map->vaddr; /* TODO: Use mapping abstraction properly */ - - dst += drm_fb_clip_offset(fb->pitches[0], fb->format, clip); - drm_fb_memcpy_toio(dst, fb->pitches[0], vmap, fb, clip); -} - -static void -mgag200_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *new_state) { - struct drm_crtc *crtc = &pipe->crtc; struct drm_device *dev = crtc->dev; struct mga_device *mdev = to_mga_device(dev); - struct mgag200_pll *pixpll = &mdev->pixpll; - struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; - struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); - struct drm_framebuffer *fb = plane_state->fb; - struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); - struct drm_rect fullscreen = { - .x1 = 0, - .x2 = fb->width, - .y1 = 0, - .y2 = fb->height, - }; - - /* - * Concurrent operations could possibly trigger a call to - * drm_connector_helper_funcs.get_modes by trying to read the - * display modes. Protect access to I/O registers by acquiring - * the I/O-register lock. - */ - mutex_lock(&mdev->rmmio_lock); - - if (mdev->type == G200_WB || mdev->type == G200_EW3) - mgag200_g200wb_hold_bmc(mdev); - - mgag200_set_format_regs(mdev, fb); - mgag200_set_mode_regs(mdev, adjusted_mode); - - pixpll->funcs->update(pixpll, &mgag200_crtc_state->pixpllc); - - if (mdev->type == G200_ER) - mgag200_g200er_reset_tagfifo(mdev); - - if (IS_G200_SE(mdev)) - mgag200_g200se_set_hiprilvl(mdev, adjusted_mode, fb); - else if (mdev->type == G200_EV) - mgag200_g200ev_set_hiprilvl(mdev); - - if (mdev->type == G200_WB || mdev->type == G200_EW3) - mgag200_g200wb_release_bmc(mdev); + const struct mgag200_device_funcs *funcs = mdev->funcs; + struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); + struct drm_property_blob *new_gamma_lut = new_crtc_state->gamma_lut; + int ret; - if (crtc_state->gamma_lut) - mgag200_crtc_set_gamma(mdev, fb->format, crtc_state->gamma_lut->data); - else - mgag200_crtc_set_gamma_linear(mdev, fb->format); + ret = drm_atomic_helper_check_crtc_state(new_crtc_state, false); + if (ret) + return ret; - mgag200_enable_display(mdev); + if (!new_crtc_state->enable) + return 0; - mgag200_handle_damage(mdev, fb, &fullscreen, &shadow_plane_state->data[0]); + if (new_crtc_state->mode_changed) { + if (funcs->pixpllc_atomic_check) { + ret = funcs->pixpllc_atomic_check(crtc, new_state); + if (ret) + return ret; + } + } - /* Always scanout image at VRAM offset 0 */ - mgag200_set_startadd(mdev, (u32)0); - mgag200_set_offset(mdev, fb); + if (new_crtc_state->color_mgmt_changed && new_gamma_lut) { + if (new_gamma_lut->length != MGAG200_LUT_SIZE * sizeof(struct drm_color_lut)) { + drm_dbg(dev, "Wrong size for gamma_lut %zu\n", new_gamma_lut->length); + return -EINVAL; + } + } - mutex_unlock(&mdev->rmmio_lock); + return drm_atomic_add_affected_planes(new_state, crtc); } -static void -mgag200_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe) +void mgag200_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *old_state) { - struct drm_crtc *crtc = &pipe->crtc; - struct mga_device *mdev = to_mga_device(crtc->dev); + struct drm_crtc_state *crtc_state = crtc->state; + struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); + struct drm_device *dev = crtc->dev; + struct mga_device *mdev = to_mga_device(dev); - mgag200_disable_display(mdev); + if (crtc_state->enable && crtc_state->color_mgmt_changed) { + const struct drm_format_info *format = mgag200_crtc_state->format; + + if (crtc_state->gamma_lut) + mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut->data); + else + mgag200_crtc_set_gamma_linear(mdev, format); + } } -static int -mgag200_simple_display_pipe_check(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *plane_state, - struct drm_crtc_state *crtc_state) +void mgag200_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *old_state) { - struct drm_plane *plane = plane_state->plane; - struct drm_device *dev = plane->dev; + struct drm_device *dev = crtc->dev; struct mga_device *mdev = to_mga_device(dev); - struct mgag200_pll *pixpll = &mdev->pixpll; + const struct mgag200_device_funcs *funcs = mdev->funcs; + struct drm_crtc_state *crtc_state = crtc->state; + struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); - struct drm_framebuffer *new_fb = plane_state->fb; - struct drm_framebuffer *fb = NULL; - int ret; + const struct drm_format_info *format = mgag200_crtc_state->format; - if (!new_fb) - return 0; + if (funcs->disable_vidrst) + funcs->disable_vidrst(mdev); - if (plane->state) - fb = plane->state->fb; + mgag200_set_format_regs(mdev, format); + mgag200_set_mode_regs(mdev, adjusted_mode); - if (!fb || (fb->format != new_fb->format)) - crtc_state->mode_changed = true; /* update PLL settings */ + if (funcs->pixpllc_atomic_update) + funcs->pixpllc_atomic_update(crtc, old_state); - if (crtc_state->mode_changed) { - ret = pixpll->funcs->compute(pixpll, crtc_state->mode.clock, - &mgag200_crtc_state->pixpllc); - if (ret) - return ret; - } + mgag200_enable_display(mdev); - if (crtc_state->color_mgmt_changed && crtc_state->gamma_lut) { - if (crtc_state->gamma_lut->length != - MGAG200_LUT_SIZE * sizeof(struct drm_color_lut)) { - drm_err(dev, "Wrong size for gamma_lut %zu\n", - crtc_state->gamma_lut->length); - return -EINVAL; - } - } - return 0; + if (funcs->enable_vidrst) + funcs->enable_vidrst(mdev); } -static void -mgag200_simple_display_pipe_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *old_state) +void mgag200_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *old_state) { - struct drm_plane *plane = &pipe->plane; - struct drm_crtc *crtc = &pipe->crtc; - struct drm_device *dev = plane->dev; - struct mga_device *mdev = to_mga_device(dev); - struct drm_plane_state *state = plane->state; - struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state); - struct drm_framebuffer *fb = state->fb; - struct drm_rect damage; - struct drm_atomic_helper_damage_iter iter; + struct mga_device *mdev = to_mga_device(crtc->dev); + const struct mgag200_device_funcs *funcs = mdev->funcs; - if (!fb) - return; + if (funcs->disable_vidrst) + funcs->disable_vidrst(mdev); - mutex_lock(&mdev->rmmio_lock); + mgag200_disable_display(mdev); - if (crtc->state->color_mgmt_changed && crtc->state->gamma_lut) - mgag200_crtc_set_gamma(mdev, fb->format, crtc->state->gamma_lut->data); + if (funcs->enable_vidrst) + funcs->enable_vidrst(mdev); +} - drm_atomic_helper_damage_iter_init(&iter, old_state, state); - drm_atomic_for_each_plane_damage(&iter, &damage) { - mgag200_handle_damage(mdev, fb, &damage, &shadow_plane_state->data[0]); - } - /* Always scanout image at VRAM offset 0 */ - mgag200_set_startadd(mdev, (u32)0); - mgag200_set_offset(mdev, fb); +void mgag200_crtc_reset(struct drm_crtc *crtc) +{ + struct mgag200_crtc_state *mgag200_crtc_state; - mutex_unlock(&mdev->rmmio_lock); + if (crtc->state) + crtc->funcs->atomic_destroy_state(crtc, crtc->state); + + mgag200_crtc_state = kzalloc(sizeof(*mgag200_crtc_state), GFP_KERNEL); + if (mgag200_crtc_state) + __drm_atomic_helper_crtc_reset(crtc, &mgag200_crtc_state->base); + else + __drm_atomic_helper_crtc_reset(crtc, NULL); } -static struct drm_crtc_state * -mgag200_simple_display_pipe_duplicate_crtc_state(struct drm_simple_display_pipe *pipe) +struct drm_crtc_state *mgag200_crtc_atomic_duplicate_state(struct drm_crtc *crtc) { - struct drm_crtc *crtc = &pipe->crtc; struct drm_crtc_state *crtc_state = crtc->state; struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); struct mgag200_crtc_state *new_mgag200_crtc_state; @@ -927,14 +688,14 @@ mgag200_simple_display_pipe_duplicate_crtc_state(struct drm_simple_display_pipe return NULL; __drm_atomic_helper_crtc_duplicate_state(crtc, &new_mgag200_crtc_state->base); + new_mgag200_crtc_state->format = mgag200_crtc_state->format; memcpy(&new_mgag200_crtc_state->pixpllc, &mgag200_crtc_state->pixpllc, sizeof(new_mgag200_crtc_state->pixpllc)); return &new_mgag200_crtc_state->base; } -static void mgag200_simple_display_pipe_destroy_crtc_state(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state) +void mgag200_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state) { struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); @@ -942,50 +703,49 @@ static void mgag200_simple_display_pipe_destroy_crtc_state(struct drm_simple_dis kfree(mgag200_crtc_state); } -static void mgag200_simple_display_pipe_reset_crtc(struct drm_simple_display_pipe *pipe) +/* + * Connector + */ + +int mgag200_vga_connector_helper_get_modes(struct drm_connector *connector) { - struct drm_crtc *crtc = &pipe->crtc; - struct mgag200_crtc_state *mgag200_crtc_state; + struct mga_device *mdev = to_mga_device(connector->dev); + int ret; - if (crtc->state) { - mgag200_simple_display_pipe_destroy_crtc_state(pipe, crtc->state); - crtc->state = NULL; /* must be set to NULL here */ - } + /* + * Protect access to I/O registers from concurrent modesetting + * by acquiring the I/O-register lock. + */ + mutex_lock(&mdev->rmmio_lock); + ret = drm_connector_helper_get_modes_from_ddc(connector); + mutex_unlock(&mdev->rmmio_lock); - mgag200_crtc_state = kzalloc(sizeof(*mgag200_crtc_state), GFP_KERNEL); - if (!mgag200_crtc_state) - return; - __drm_atomic_helper_crtc_reset(crtc, &mgag200_crtc_state->base); + return ret; } -static const struct drm_simple_display_pipe_funcs -mgag200_simple_display_pipe_funcs = { - .mode_valid = mgag200_simple_display_pipe_mode_valid, - .enable = mgag200_simple_display_pipe_enable, - .disable = mgag200_simple_display_pipe_disable, - .check = mgag200_simple_display_pipe_check, - .update = mgag200_simple_display_pipe_update, - .reset_crtc = mgag200_simple_display_pipe_reset_crtc, - .duplicate_crtc_state = mgag200_simple_display_pipe_duplicate_crtc_state, - .destroy_crtc_state = mgag200_simple_display_pipe_destroy_crtc_state, - DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, -}; - -static const uint32_t mgag200_simple_display_pipe_formats[] = { - DRM_FORMAT_XRGB8888, - DRM_FORMAT_RGB565, - DRM_FORMAT_RGB888, -}; - -static const uint64_t mgag200_simple_display_pipe_fmtmods[] = { - DRM_FORMAT_MOD_LINEAR, - DRM_FORMAT_MOD_INVALID -}; - /* * Mode config */ +static void mgag200_mode_config_helper_atomic_commit_tail(struct drm_atomic_state *state) +{ + struct mga_device *mdev = to_mga_device(state->dev); + + /* + * Concurrent operations could possibly trigger a call to + * drm_connector_helper_funcs.get_modes by trying to read the + * display modes. Protect access to I/O registers by acquiring + * the I/O-register lock. + */ + mutex_lock(&mdev->rmmio_lock); + drm_atomic_helper_commit_tail(state); + mutex_unlock(&mdev->rmmio_lock); +} + +static const struct drm_mode_config_helper_funcs mgag200_mode_config_helper_funcs = { + .atomic_commit_tail = mgag200_mode_config_helper_atomic_commit_tail, +}; + /* Calculates a mode's required memory bandwidth (in KiB/sec). */ static uint32_t mgag200_calculate_mode_bandwidth(const struct drm_display_mode *mode, unsigned int bits_per_pixel) @@ -1048,23 +808,16 @@ static const struct drm_mode_config_funcs mgag200_mode_config_funcs = { .atomic_commit = drm_atomic_helper_commit, }; -int mgag200_modeset_init(struct mga_device *mdev, resource_size_t vram_available) +int mgag200_mode_config_init(struct mga_device *mdev, resource_size_t vram_available) { struct drm_device *dev = &mdev->base; - struct mga_i2c_chan *i2c = &mdev->i2c; - struct drm_connector *connector = &mdev->connector; - struct drm_simple_display_pipe *pipe = &mdev->display_pipe; - size_t format_count = ARRAY_SIZE(mgag200_simple_display_pipe_formats); int ret; - mgag200_init_regs(mdev); - mdev->vram_available = vram_available; ret = drmm_mode_config_init(dev); if (ret) { - drm_err(dev, "drmm_mode_config_init() failed, error %d\n", - ret); + drm_err(dev, "drmm_mode_config_init() failed: %d\n", ret); return ret; } @@ -1073,48 +826,7 @@ int mgag200_modeset_init(struct mga_device *mdev, resource_size_t vram_available dev->mode_config.preferred_depth = 24; dev->mode_config.fb_base = mdev->vram_res->start; dev->mode_config.funcs = &mgag200_mode_config_funcs; - - ret = mgag200_i2c_init(mdev, i2c); - if (ret) { - drm_err(dev, "failed to add DDC bus: %d\n", ret); - return ret; - } - - ret = drm_connector_init_with_ddc(dev, connector, - &mga_vga_connector_funcs, - DRM_MODE_CONNECTOR_VGA, - &i2c->adapter); - if (ret) { - drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret); - return ret; - } - drm_connector_helper_add(connector, &mga_vga_connector_helper_funcs); - - ret = mgag200_pixpll_init(&mdev->pixpll, mdev); - if (ret) - return ret; - - ret = drm_simple_display_pipe_init(dev, pipe, - &mgag200_simple_display_pipe_funcs, - mgag200_simple_display_pipe_formats, - format_count, - mgag200_simple_display_pipe_fmtmods, - connector); - if (ret) { - drm_err(dev, - "drm_simple_display_pipe_init() failed, error %d\n", - ret); - return ret; - } - - drm_plane_enable_fb_damage_clips(&pipe->plane); - - /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */ - drm_mode_crtc_set_gamma_size(&pipe->crtc, MGAG200_LUT_SIZE); - - drm_crtc_enable_color_mgmt(&pipe->crtc, 0, false, MGAG200_LUT_SIZE); - - drm_mode_config_reset(dev); + dev->mode_config.helper_private = &mgag200_mode_config_helper_funcs; return 0; } diff --git a/drivers/gpu/drm/mgag200/mgag200_pll.c b/drivers/gpu/drm/mgag200/mgag200_pll.c deleted file mode 100644 index 8065ca5d8de9..000000000000 --- a/drivers/gpu/drm/mgag200/mgag200_pll.c +++ /dev/null @@ -1,997 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only - -#include <linux/delay.h> - -#include "mgag200_drv.h" - -/* - * G200 - */ - -static int mgag200_pixpll_compute_g200(struct mgag200_pll *pixpll, long clock, - struct mgag200_pll_values *pixpllc) -{ - struct mga_device *mdev = pixpll->mdev; - struct drm_device *dev = &mdev->base; - struct mgag200_g200_device *g200 = to_mgag200_g200_device(dev); - const int post_div_max = 7; - const int in_div_min = 1; - const int in_div_max = 6; - const int feed_div_min = 7; - const int feed_div_max = 127; - u8 testp, testm, testn; - u8 n = 0, m = 0, p, s; - long f_vco; - long computed; - long delta, tmp_delta; - long ref_clk = g200->ref_clk; - long p_clk_min = g200->pclk_min; - long p_clk_max = g200->pclk_max; - - if (clock > p_clk_max) { - drm_err(dev, "Pixel Clock %ld too high\n", clock); - return -EINVAL; - } - - if (clock < p_clk_min >> 3) - clock = p_clk_min >> 3; - - f_vco = clock; - for (testp = 0; - testp <= post_div_max && f_vco < p_clk_min; - testp = (testp << 1) + 1, f_vco <<= 1) - ; - p = testp + 1; - - delta = clock; - - for (testm = in_div_min; testm <= in_div_max; testm++) { - for (testn = feed_div_min; testn <= feed_div_max; testn++) { - computed = ref_clk * (testn + 1) / (testm + 1); - if (computed < f_vco) - tmp_delta = f_vco - computed; - else - tmp_delta = computed - f_vco; - if (tmp_delta < delta) { - delta = tmp_delta; - m = testm + 1; - n = testn + 1; - } - } - } - f_vco = ref_clk * n / m; - if (f_vco < 100000) - s = 0; - else if (f_vco < 140000) - s = 1; - else if (f_vco < 180000) - s = 2; - else - s = 3; - - drm_dbg_kms(dev, "clock: %ld vco: %ld m: %d n: %d p: %d s: %d\n", - clock, f_vco, m, n, p, s); - - pixpllc->m = m; - pixpllc->n = n; - pixpllc->p = p; - pixpllc->s = s; - - return 0; -} - -static void -mgag200_pixpll_update_g200(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc) -{ - struct mga_device *mdev = pixpll->mdev; - unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; - u8 xpixpllcm, xpixpllcn, xpixpllcp; - - pixpllcm = pixpllc->m - 1; - pixpllcn = pixpllc->n - 1; - pixpllcp = pixpllc->p - 1; - pixpllcs = pixpllc->s; - - xpixpllcm = pixpllcm; - xpixpllcn = pixpllcn; - xpixpllcp = (pixpllcs << 3) | pixpllcp; - - WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); - - WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm); - WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn); - WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp); -} - -static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200 = { - .compute = mgag200_pixpll_compute_g200, - .update = mgag200_pixpll_update_g200, -}; - -/* - * G200SE - */ - -static int mgag200_pixpll_compute_g200se_00(struct mgag200_pll *pixpll, long clock, - struct mgag200_pll_values *pixpllc) -{ - static const unsigned int vcomax = 320000; - static const unsigned int vcomin = 160000; - static const unsigned int pllreffreq = 25000; - - unsigned int delta, tmpdelta, permitteddelta; - unsigned int testp, testm, testn; - unsigned int p, m, n, s; - unsigned int computed; - - m = n = p = s = 0; - delta = 0xffffffff; - permitteddelta = clock * 5 / 1000; - - for (testp = 8; testp > 0; testp /= 2) { - if (clock * testp > vcomax) - continue; - if (clock * testp < vcomin) - continue; - - for (testn = 17; testn < 256; testn++) { - for (testm = 1; testm < 32; testm++) { - computed = (pllreffreq * testn) / (testm * testp); - if (computed > clock) - tmpdelta = computed - clock; - else - tmpdelta = clock - computed; - if (tmpdelta < delta) { - delta = tmpdelta; - m = testm; - n = testn; - p = testp; - } - } - } - } - - if (delta > permitteddelta) { - pr_warn("PLL delta too large\n"); - return -EINVAL; - } - - pixpllc->m = m; - pixpllc->n = n; - pixpllc->p = p; - pixpllc->s = s; - - return 0; -} - -static void mgag200_pixpll_update_g200se_00(struct mgag200_pll *pixpll, - const struct mgag200_pll_values *pixpllc) -{ - unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; - u8 xpixpllcm, xpixpllcn, xpixpllcp; - struct mga_device *mdev = pixpll->mdev; - - pixpllcm = pixpllc->m - 1; - pixpllcn = pixpllc->n - 1; - pixpllcp = pixpllc->p - 1; - pixpllcs = pixpllc->s; - - xpixpllcm = pixpllcm | ((pixpllcn & BIT(8)) >> 1); - xpixpllcn = pixpllcn; - xpixpllcp = (pixpllcs << 3) | pixpllcp; - - WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); - - WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm); - WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn); - WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp); -} - -static int mgag200_pixpll_compute_g200se_04(struct mgag200_pll *pixpll, long clock, - struct mgag200_pll_values *pixpllc) -{ - static const unsigned int vcomax = 1600000; - static const unsigned int vcomin = 800000; - static const unsigned int pllreffreq = 25000; - static const unsigned int pvalues_e4[] = {16, 14, 12, 10, 8, 6, 4, 2, 1}; - - unsigned int delta, tmpdelta, permitteddelta; - unsigned int testp, testm, testn; - unsigned int p, m, n, s; - unsigned int computed; - unsigned int fvv; - unsigned int i; - - m = n = p = s = 0; - delta = 0xffffffff; - - if (clock < 25000) - clock = 25000; - clock = clock * 2; - - /* Permited delta is 0.5% as VESA Specification */ - permitteddelta = clock * 5 / 1000; - - for (i = 0 ; i < ARRAY_SIZE(pvalues_e4); i++) { - testp = pvalues_e4[i]; - - if ((clock * testp) > vcomax) - continue; - if ((clock * testp) < vcomin) - continue; - - for (testn = 50; testn <= 256; testn++) { - for (testm = 1; testm <= 32; testm++) { - computed = (pllreffreq * testn) / (testm * testp); - if (computed > clock) - tmpdelta = computed - clock; - else - tmpdelta = clock - computed; - - if (tmpdelta < delta) { - delta = tmpdelta; - m = testm; - n = testn; - p = testp; - } - } - } - } - - fvv = pllreffreq * n / m; - fvv = (fvv - 800000) / 50000; - if (fvv > 15) - fvv = 15; - s = fvv << 1; - - if (delta > permitteddelta) { - pr_warn("PLL delta too large\n"); - return -EINVAL; - } - - pixpllc->m = m; - pixpllc->n = n; - pixpllc->p = p; - pixpllc->s = s; - - return 0; -} - -static void mgag200_pixpll_update_g200se_04(struct mgag200_pll *pixpll, - const struct mgag200_pll_values *pixpllc) -{ - unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; - u8 xpixpllcm, xpixpllcn, xpixpllcp; - struct mga_device *mdev = pixpll->mdev; - - pixpllcm = pixpllc->m - 1; - pixpllcn = pixpllc->n - 1; - pixpllcp = pixpllc->p - 1; - pixpllcs = pixpllc->s; - - xpixpllcm = pixpllcm | ((pixpllcn & BIT(8)) >> 1); - xpixpllcn = pixpllcn; - xpixpllcp = (pixpllcs << 3) | pixpllcp; - - WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); - - WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm); - WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn); - WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp); - - WREG_DAC(0x1a, 0x09); - msleep(20); - WREG_DAC(0x1a, 0x01); -} - -static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200se_00 = { - .compute = mgag200_pixpll_compute_g200se_00, - .update = mgag200_pixpll_update_g200se_00, -}; - -static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200se_04 = { - .compute = mgag200_pixpll_compute_g200se_04, - .update = mgag200_pixpll_update_g200se_04, -}; - -/* - * G200WB - */ - -static int mgag200_pixpll_compute_g200wb(struct mgag200_pll *pixpll, long clock, - struct mgag200_pll_values *pixpllc) -{ - static const unsigned int vcomax = 550000; - static const unsigned int vcomin = 150000; - static const unsigned int pllreffreq = 48000; - - unsigned int delta, tmpdelta; - unsigned int testp, testm, testn; - unsigned int p, m, n, s; - unsigned int computed; - - m = n = p = s = 0; - delta = 0xffffffff; - - for (testp = 1; testp < 9; testp++) { - if (clock * testp > vcomax) - continue; - if (clock * testp < vcomin) - continue; - - for (testm = 1; testm < 17; testm++) { - for (testn = 1; testn < 151; testn++) { - computed = (pllreffreq * testn) / (testm * testp); - if (computed > clock) - tmpdelta = computed - clock; - else - tmpdelta = clock - computed; - if (tmpdelta < delta) { - delta = tmpdelta; - n = testn; - m = testm; - p = testp; - s = 0; - } - } - } - } - - pixpllc->m = m; - pixpllc->n = n; - pixpllc->p = p; - pixpllc->s = s; - - return 0; -} - -static void -mgag200_pixpll_update_g200wb(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc) -{ - unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; - u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; - int i, j, tmpcount, vcount; - struct mga_device *mdev = pixpll->mdev; - bool pll_locked = false; - - pixpllcm = pixpllc->m - 1; - pixpllcn = pixpllc->n - 1; - pixpllcp = pixpllc->p - 1; - pixpllcs = pixpllc->s; - - xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm; - xpixpllcn = pixpllcn; - xpixpllcp = ((pixpllcn & GENMASK(10, 9)) >> 3) | (pixpllcs << 3) | pixpllcp; - - WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); - - for (i = 0; i <= 32 && pll_locked == false; i++) { - if (i > 0) { - WREG8(MGAREG_CRTC_INDEX, 0x1e); - tmp = RREG8(MGAREG_CRTC_DATA); - if (tmp < 0xff) - WREG8(MGAREG_CRTC_DATA, tmp+1); - } - - /* set pixclkdis to 1 */ - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; - WREG8(DAC_DATA, tmp); - - WREG8(DAC_INDEX, MGA1064_REMHEADCTL); - tmp = RREG8(DAC_DATA); - tmp |= MGA1064_REMHEADCTL_CLKDIS; - WREG8(DAC_DATA, tmp); - - /* select PLL Set C */ - tmp = RREG8(MGAREG_MEM_MISC_READ); - tmp |= 0x3 << 2; - WREG8(MGAREG_MEM_MISC_WRITE, tmp); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN | 0x80; - WREG8(DAC_DATA, tmp); - - udelay(500); - - /* reset the PLL */ - WREG8(DAC_INDEX, MGA1064_VREF_CTL); - tmp = RREG8(DAC_DATA); - tmp &= ~0x04; - WREG8(DAC_DATA, tmp); - - udelay(50); - - /* program pixel pll register */ - WREG_DAC(MGA1064_WB_PIX_PLLC_N, xpixpllcn); - WREG_DAC(MGA1064_WB_PIX_PLLC_M, xpixpllcm); - WREG_DAC(MGA1064_WB_PIX_PLLC_P, xpixpllcp); - - udelay(50); - - /* turn pll on */ - WREG8(DAC_INDEX, MGA1064_VREF_CTL); - tmp = RREG8(DAC_DATA); - tmp |= 0x04; - WREG_DAC(MGA1064_VREF_CTL, tmp); - - udelay(500); - - /* select the pixel pll */ - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; - tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; - WREG8(DAC_DATA, tmp); - - WREG8(DAC_INDEX, MGA1064_REMHEADCTL); - tmp = RREG8(DAC_DATA); - tmp &= ~MGA1064_REMHEADCTL_CLKSL_MSK; - tmp |= MGA1064_REMHEADCTL_CLKSL_PLL; - WREG8(DAC_DATA, tmp); - - /* reset dotclock rate bit */ - WREG8(MGAREG_SEQ_INDEX, 1); - tmp = RREG8(MGAREG_SEQ_DATA); - tmp &= ~0x8; - WREG8(MGAREG_SEQ_DATA, tmp); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; - WREG8(DAC_DATA, tmp); - - vcount = RREG8(MGAREG_VCOUNT); - - for (j = 0; j < 30 && pll_locked == false; j++) { - tmpcount = RREG8(MGAREG_VCOUNT); - if (tmpcount < vcount) - vcount = 0; - if ((tmpcount - vcount) > 2) - pll_locked = true; - else - udelay(5); - } - } - - WREG8(DAC_INDEX, MGA1064_REMHEADCTL); - tmp = RREG8(DAC_DATA); - tmp &= ~MGA1064_REMHEADCTL_CLKDIS; - WREG_DAC(MGA1064_REMHEADCTL, tmp); -} - -static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200wb = { - .compute = mgag200_pixpll_compute_g200wb, - .update = mgag200_pixpll_update_g200wb, -}; - -/* - * G200EV - */ - -static int mgag200_pixpll_compute_g200ev(struct mgag200_pll *pixpll, long clock, - struct mgag200_pll_values *pixpllc) -{ - static const unsigned int vcomax = 550000; - static const unsigned int vcomin = 150000; - static const unsigned int pllreffreq = 50000; - - unsigned int delta, tmpdelta; - unsigned int testp, testm, testn; - unsigned int p, m, n, s; - unsigned int computed; - - m = n = p = s = 0; - delta = 0xffffffff; - - for (testp = 16; testp > 0; testp--) { - if (clock * testp > vcomax) - continue; - if (clock * testp < vcomin) - continue; - - for (testn = 1; testn < 257; testn++) { - for (testm = 1; testm < 17; testm++) { - computed = (pllreffreq * testn) / - (testm * testp); - if (computed > clock) - tmpdelta = computed - clock; - else - tmpdelta = clock - computed; - if (tmpdelta < delta) { - delta = tmpdelta; - n = testn; - m = testm; - p = testp; - } - } - } - } - - pixpllc->m = m; - pixpllc->n = n; - pixpllc->p = p; - pixpllc->s = s; - - return 0; -} - -static void -mgag200_pixpll_update_g200ev(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc) -{ - unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; - u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; - struct mga_device *mdev = pixpll->mdev; - - pixpllcm = pixpllc->m - 1; - pixpllcn = pixpllc->n - 1; - pixpllcp = pixpllc->p - 1; - pixpllcs = pixpllc->s; - - xpixpllcm = pixpllcm; - xpixpllcn = pixpllcn; - xpixpllcp = (pixpllcs << 3) | pixpllcp; - - WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; - WREG8(DAC_DATA, tmp); - - tmp = RREG8(MGAREG_MEM_MISC_READ); - tmp |= 0x3 << 2; - WREG8(MGAREG_MEM_MISC_WRITE, tmp); - - WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT); - tmp = RREG8(DAC_DATA); - WREG8(DAC_DATA, tmp & ~0x40); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; - WREG8(DAC_DATA, tmp); - - WREG_DAC(MGA1064_EV_PIX_PLLC_M, xpixpllcm); - WREG_DAC(MGA1064_EV_PIX_PLLC_N, xpixpllcn); - WREG_DAC(MGA1064_EV_PIX_PLLC_P, xpixpllcp); - - udelay(50); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; - WREG8(DAC_DATA, tmp); - - udelay(500); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; - tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; - WREG8(DAC_DATA, tmp); - - WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT); - tmp = RREG8(DAC_DATA); - WREG8(DAC_DATA, tmp | 0x40); - - tmp = RREG8(MGAREG_MEM_MISC_READ); - tmp |= (0x3 << 2); - WREG8(MGAREG_MEM_MISC_WRITE, tmp); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; - WREG8(DAC_DATA, tmp); -} - -static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200ev = { - .compute = mgag200_pixpll_compute_g200ev, - .update = mgag200_pixpll_update_g200ev, -}; - -/* - * G200EH - */ - -static int mgag200_pixpll_compute_g200eh(struct mgag200_pll *pixpll, long clock, - struct mgag200_pll_values *pixpllc) -{ - static const unsigned int vcomax = 800000; - static const unsigned int vcomin = 400000; - static const unsigned int pllreffreq = 33333; - - unsigned int delta, tmpdelta; - unsigned int testp, testm, testn; - unsigned int p, m, n, s; - unsigned int computed; - - m = n = p = s = 0; - delta = 0xffffffff; - - for (testp = 16; testp > 0; testp >>= 1) { - if (clock * testp > vcomax) - continue; - if (clock * testp < vcomin) - continue; - - for (testm = 1; testm < 33; testm++) { - for (testn = 17; testn < 257; testn++) { - computed = (pllreffreq * testn) / (testm * testp); - if (computed > clock) - tmpdelta = computed - clock; - else - tmpdelta = clock - computed; - if (tmpdelta < delta) { - delta = tmpdelta; - n = testn; - m = testm; - p = testp; - } - } - } - } - - pixpllc->m = m; - pixpllc->n = n; - pixpllc->p = p; - pixpllc->s = s; - - return 0; -} - -static void -mgag200_pixpll_update_g200eh(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc) -{ - unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; - u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; - int i, j, tmpcount, vcount; - struct mga_device *mdev = pixpll->mdev; - bool pll_locked = false; - - pixpllcm = pixpllc->m - 1; - pixpllcn = pixpllc->n - 1; - pixpllcp = pixpllc->p - 1; - pixpllcs = pixpllc->s; - - xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm; - xpixpllcn = pixpllcn; - xpixpllcp = (pixpllcs << 3) | pixpllcp; - - WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); - - for (i = 0; i <= 32 && pll_locked == false; i++) { - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; - WREG8(DAC_DATA, tmp); - - tmp = RREG8(MGAREG_MEM_MISC_READ); - tmp |= 0x3 << 2; - WREG8(MGAREG_MEM_MISC_WRITE, tmp); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; - WREG8(DAC_DATA, tmp); - - udelay(500); - - WREG_DAC(MGA1064_EH_PIX_PLLC_M, xpixpllcm); - WREG_DAC(MGA1064_EH_PIX_PLLC_N, xpixpllcn); - WREG_DAC(MGA1064_EH_PIX_PLLC_P, xpixpllcp); - - udelay(500); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; - tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; - WREG8(DAC_DATA, tmp); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; - tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; - WREG8(DAC_DATA, tmp); - - vcount = RREG8(MGAREG_VCOUNT); - - for (j = 0; j < 30 && pll_locked == false; j++) { - tmpcount = RREG8(MGAREG_VCOUNT); - if (tmpcount < vcount) - vcount = 0; - if ((tmpcount - vcount) > 2) - pll_locked = true; - else - udelay(5); - } - } -} - -static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200eh = { - .compute = mgag200_pixpll_compute_g200eh, - .update = mgag200_pixpll_update_g200eh, -}; - -/* - * G200EH3 - */ - -static int mgag200_pixpll_compute_g200eh3(struct mgag200_pll *pixpll, long clock, - struct mgag200_pll_values *pixpllc) -{ - static const unsigned int vcomax = 3000000; - static const unsigned int vcomin = 1500000; - static const unsigned int pllreffreq = 25000; - - unsigned int delta, tmpdelta; - unsigned int testp, testm, testn; - unsigned int p, m, n, s; - unsigned int computed; - - m = n = p = s = 0; - delta = 0xffffffff; - testp = 0; - - for (testm = 150; testm >= 6; testm--) { - if (clock * testm > vcomax) - continue; - if (clock * testm < vcomin) - continue; - for (testn = 120; testn >= 60; testn--) { - computed = (pllreffreq * testn) / testm; - if (computed > clock) - tmpdelta = computed - clock; - else - tmpdelta = clock - computed; - if (tmpdelta < delta) { - delta = tmpdelta; - n = testn + 1; - m = testm + 1; - p = testp + 1; - } - if (delta == 0) - break; - } - if (delta == 0) - break; - } - - pixpllc->m = m; - pixpllc->n = n; - pixpllc->p = p; - pixpllc->s = s; - - return 0; -} - -static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200eh3 = { - .compute = mgag200_pixpll_compute_g200eh3, - .update = mgag200_pixpll_update_g200eh, // same as G200EH -}; - -/* - * G200ER - */ - -static int mgag200_pixpll_compute_g200er(struct mgag200_pll *pixpll, long clock, - struct mgag200_pll_values *pixpllc) -{ - static const unsigned int vcomax = 1488000; - static const unsigned int vcomin = 1056000; - static const unsigned int pllreffreq = 48000; - static const unsigned int m_div_val[] = { 1, 2, 4, 8 }; - - unsigned int delta, tmpdelta; - int testr, testn, testm, testo; - unsigned int p, m, n, s; - unsigned int computed, vco; - - m = n = p = s = 0; - delta = 0xffffffff; - - for (testr = 0; testr < 4; testr++) { - if (delta == 0) - break; - for (testn = 5; testn < 129; testn++) { - if (delta == 0) - break; - for (testm = 3; testm >= 0; testm--) { - if (delta == 0) - break; - for (testo = 5; testo < 33; testo++) { - vco = pllreffreq * (testn + 1) / - (testr + 1); - if (vco < vcomin) - continue; - if (vco > vcomax) - continue; - computed = vco / (m_div_val[testm] * (testo + 1)); - if (computed > clock) - tmpdelta = computed - clock; - else - tmpdelta = clock - computed; - if (tmpdelta < delta) { - delta = tmpdelta; - m = (testm | (testo << 3)) + 1; - n = testn + 1; - p = testr + 1; - s = testr; - } - } - } - } - } - - pixpllc->m = m; - pixpllc->n = n; - pixpllc->p = p; - pixpllc->s = s; - - return 0; -} - -static void -mgag200_pixpll_update_g200er(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc) -{ - unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; - u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; - struct mga_device *mdev = pixpll->mdev; - - pixpllcm = pixpllc->m - 1; - pixpllcn = pixpllc->n - 1; - pixpllcp = pixpllc->p - 1; - pixpllcs = pixpllc->s; - - xpixpllcm = pixpllcm; - xpixpllcn = pixpllcn; - xpixpllcp = (pixpllcs << 3) | pixpllcp; - - WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; - WREG8(DAC_DATA, tmp); - - WREG8(DAC_INDEX, MGA1064_REMHEADCTL); - tmp = RREG8(DAC_DATA); - tmp |= MGA1064_REMHEADCTL_CLKDIS; - WREG8(DAC_DATA, tmp); - - tmp = RREG8(MGAREG_MEM_MISC_READ); - tmp |= (0x3<<2) | 0xc0; - WREG8(MGAREG_MEM_MISC_WRITE, tmp); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; - tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; - WREG8(DAC_DATA, tmp); - - udelay(500); - - WREG_DAC(MGA1064_ER_PIX_PLLC_N, xpixpllcn); - WREG_DAC(MGA1064_ER_PIX_PLLC_M, xpixpllcm); - WREG_DAC(MGA1064_ER_PIX_PLLC_P, xpixpllcp); - - udelay(50); -} - -static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200er = { - .compute = mgag200_pixpll_compute_g200er, - .update = mgag200_pixpll_update_g200er, -}; - -/* - * G200EW3 - */ - -static int mgag200_pixpll_compute_g200ew3(struct mgag200_pll *pixpll, long clock, - struct mgag200_pll_values *pixpllc) -{ - static const unsigned int vcomax = 800000; - static const unsigned int vcomin = 400000; - static const unsigned int pllreffreq = 25000; - - unsigned int delta, tmpdelta; - unsigned int testp, testm, testn, testp2; - unsigned int p, m, n, s; - unsigned int computed; - - m = n = p = s = 0; - delta = 0xffffffff; - - for (testp = 1; testp < 8; testp++) { - for (testp2 = 1; testp2 < 8; testp2++) { - if (testp < testp2) - continue; - if ((clock * testp * testp2) > vcomax) - continue; - if ((clock * testp * testp2) < vcomin) - continue; - for (testm = 1; testm < 26; testm++) { - for (testn = 32; testn < 2048 ; testn++) { - computed = (pllreffreq * testn) / (testm * testp * testp2); - if (computed > clock) - tmpdelta = computed - clock; - else - tmpdelta = clock - computed; - if (tmpdelta < delta) { - delta = tmpdelta; - m = testm + 1; - n = testn + 1; - p = testp + 1; - s = testp2; - } - } - } - } - } - - pixpllc->m = m; - pixpllc->n = n; - pixpllc->p = p; - pixpllc->s = s; - - return 0; -} - -static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200ew3 = { - .compute = mgag200_pixpll_compute_g200ew3, - .update = mgag200_pixpll_update_g200wb, // same as G200WB -}; - -/* - * PLL initialization - */ - -int mgag200_pixpll_init(struct mgag200_pll *pixpll, struct mga_device *mdev) -{ - struct drm_device *dev = &mdev->base; - struct mgag200_g200se_device *g200se; - - pixpll->mdev = mdev; - - switch (mdev->type) { - case G200_PCI: - case G200_AGP: - pixpll->funcs = &mgag200_pixpll_funcs_g200; - break; - case G200_SE_A: - case G200_SE_B: - g200se = to_mgag200_g200se_device(dev); - - if (g200se->unique_rev_id >= 0x04) - pixpll->funcs = &mgag200_pixpll_funcs_g200se_04; - else - pixpll->funcs = &mgag200_pixpll_funcs_g200se_00; - break; - case G200_WB: - pixpll->funcs = &mgag200_pixpll_funcs_g200wb; - break; - case G200_EV: - pixpll->funcs = &mgag200_pixpll_funcs_g200ev; - break; - case G200_EH: - pixpll->funcs = &mgag200_pixpll_funcs_g200eh; - break; - case G200_EH3: - pixpll->funcs = &mgag200_pixpll_funcs_g200eh3; - break; - case G200_ER: - pixpll->funcs = &mgag200_pixpll_funcs_g200er; - break; - case G200_EW3: - pixpll->funcs = &mgag200_pixpll_funcs_g200ew3; - break; - default: - drm_err(dev, "unknown device type %d\n", mdev->type); - return -ENODEV; - } - - return 0; -} diff --git a/drivers/gpu/drm/mgag200/mgag200_reg.h b/drivers/gpu/drm/mgag200/mgag200_reg.h index 99a9ab7d9119..1019ffd6c260 100644 --- a/drivers/gpu/drm/mgag200/mgag200_reg.h +++ b/drivers/gpu/drm/mgag200/mgag200_reg.h @@ -96,7 +96,7 @@ #define MGAREG_SRCORG 0x2cb4 #define MGAREG_DSTORG 0x2cb8 -/* add or or this to one of the previous "power registers" to start +/* add or this to one of the previous "power registers" to start the drawing engine */ #define MGAREG_EXEC 0x0100 diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 1ed4cd09dbf8..1d0bafedd585 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -355,7 +355,7 @@ static int msm_init_vram(struct drm_device *dev) DRM_INFO("using VRAM carveout: %lx@%pa\n", size, &r.start); /* if we have no IOMMU, then we need to use carveout allocator. - * Grab the entire CMA chunk carved out in early startup in + * Grab the entire DMA chunk carved out in early startup in * mach-msm: */ } else if (!msm_use_mmu(dev)) { diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index b3689a2d27d7..7d5fb0fc22dd 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -27,7 +27,6 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_fb_helper.h> #include <drm/display/drm_dsc.h> diff --git a/drivers/gpu/drm/mxsfb/Kconfig b/drivers/gpu/drm/mxsfb/Kconfig index 873551b4552f..116f8168bda4 100644 --- a/drivers/gpu/drm/mxsfb/Kconfig +++ b/drivers/gpu/drm/mxsfb/Kconfig @@ -10,7 +10,7 @@ config DRM_MXSFB depends on COMMON_CLK select DRM_MXS select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_PANEL select DRM_PANEL_BRIDGE help @@ -26,7 +26,7 @@ config DRM_IMX_LCDIF depends on COMMON_CLK select DRM_MXS select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_PANEL select DRM_PANEL_BRIDGE help diff --git a/drivers/gpu/drm/mxsfb/lcdif_drv.c b/drivers/gpu/drm/mxsfb/lcdif_drv.c index befad33dcb95..05db135800db 100644 --- a/drivers/gpu/drm/mxsfb/lcdif_drv.c +++ b/drivers/gpu/drm/mxsfb/lcdif_drv.c @@ -20,7 +20,7 @@ #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_mode_config.h> #include <drm/drm_module.h> @@ -199,11 +199,11 @@ static void lcdif_unload(struct drm_device *drm) drm->dev_private = NULL; } -DEFINE_DRM_GEM_CMA_FOPS(fops); +DEFINE_DRM_GEM_DMA_FOPS(fops); static const struct drm_driver lcdif_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, - DRM_GEM_CMA_DRIVER_OPS, + DRM_GEM_DMA_DRIVER_OPS, .fops = &fops, .name = "imx-lcdif", .desc = "i.MX LCDIF Controller DRM", diff --git a/drivers/gpu/drm/mxsfb/lcdif_kms.c b/drivers/gpu/drm/mxsfb/lcdif_kms.c index 1bec1279c8b5..c7efc0d27f0e 100644 --- a/drivers/gpu/drm/mxsfb/lcdif_kms.c +++ b/drivers/gpu/drm/mxsfb/lcdif_kms.c @@ -18,12 +18,11 @@ #include <drm/drm_crtc.h> #include <drm/drm_encoder.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_plane.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_vblank.h> #include "lcdif_drv.h" @@ -297,7 +296,7 @@ static void lcdif_crtc_atomic_enable(struct drm_crtc *crtc, lcdif_crtc_mode_set_nofb(lcdif, bridge_state, bus_format); /* Write cur_buf as well to avoid an initial corrupt frame */ - paddr = drm_fb_cma_get_gem_addr(new_pstate->fb, new_pstate, 0); + paddr = drm_fb_dma_get_gem_addr(new_pstate->fb, new_pstate, 0); if (paddr) { writel(lower_32_bits(paddr), lcdif->base + LCDC_V8_CTRLDESCL_LOW0_4); @@ -393,8 +392,8 @@ static int lcdif_plane_atomic_check(struct drm_plane *plane, &lcdif->crtc); return drm_atomic_helper_check_plane_state(plane_state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, false, true); } @@ -406,7 +405,7 @@ static void lcdif_plane_primary_atomic_update(struct drm_plane *plane, plane); dma_addr_t paddr; - paddr = drm_fb_cma_get_gem_addr(new_pstate->fb, new_pstate, 0); + paddr = drm_fb_dma_get_gem_addr(new_pstate->fb, new_pstate, 0); if (paddr) { writel(lower_32_bits(paddr), lcdif->base + LCDC_V8_CTRLDESCL_LOW0_4); diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c index 55aad92e08ba..b29b332ed381 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c @@ -22,7 +22,7 @@ #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_mode_config.h> #include <drm/drm_module.h> @@ -324,11 +324,11 @@ static void mxsfb_unload(struct drm_device *drm) pm_runtime_disable(drm->dev); } -DEFINE_DRM_GEM_CMA_FOPS(fops); +DEFINE_DRM_GEM_DMA_FOPS(fops); static const struct drm_driver mxsfb_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, - DRM_GEM_CMA_DRIVER_OPS, + DRM_GEM_DMA_DRIVER_OPS, .fops = &fops, .name = "mxsfb-drm", .desc = "MXSFB Controller DRM", diff --git a/drivers/gpu/drm/mxsfb/mxsfb_kms.c b/drivers/gpu/drm/mxsfb/mxsfb_kms.c index e38ce5737a5f..3bcc9c0f2019 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_kms.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_kms.c @@ -20,13 +20,12 @@ #include <drm/drm_bridge.h> #include <drm/drm_crtc.h> #include <drm/drm_encoder.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_plane.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_vblank.h> #include "mxsfb_drv.h" @@ -353,7 +352,7 @@ static void mxsfb_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_bridge_state *bridge_state = NULL; struct drm_device *drm = mxsfb->drm; u32 bus_format = 0; - dma_addr_t paddr; + dma_addr_t dma_addr; pm_runtime_get_sync(drm->dev); mxsfb_enable_axi_clk(mxsfb); @@ -389,10 +388,10 @@ static void mxsfb_crtc_atomic_enable(struct drm_crtc *crtc, mxsfb_crtc_mode_set_nofb(mxsfb, bridge_state, bus_format); /* Write cur_buf as well to avoid an initial corrupt frame */ - paddr = drm_fb_cma_get_gem_addr(new_pstate->fb, new_pstate, 0); - if (paddr) { - writel(paddr, mxsfb->base + mxsfb->devdata->cur_buf); - writel(paddr, mxsfb->base + mxsfb->devdata->next_buf); + dma_addr = drm_fb_dma_get_gem_addr(new_pstate->fb, new_pstate, 0); + if (dma_addr) { + writel(dma_addr, mxsfb->base + mxsfb->devdata->cur_buf); + writel(dma_addr, mxsfb->base + mxsfb->devdata->next_buf); } mxsfb_enable_controller(mxsfb); @@ -531,8 +530,8 @@ static int mxsfb_plane_atomic_check(struct drm_plane *plane, &mxsfb->crtc); return drm_atomic_helper_check_plane_state(plane_state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, false, true); } @@ -542,11 +541,11 @@ static void mxsfb_plane_primary_atomic_update(struct drm_plane *plane, struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(plane->dev); struct drm_plane_state *new_pstate = drm_atomic_get_new_plane_state(state, plane); - dma_addr_t paddr; + dma_addr_t dma_addr; - paddr = drm_fb_cma_get_gem_addr(new_pstate->fb, new_pstate, 0); - if (paddr) - writel(paddr, mxsfb->base + mxsfb->devdata->next_buf); + dma_addr = drm_fb_dma_get_gem_addr(new_pstate->fb, new_pstate, 0); + if (dma_addr) + writel(dma_addr, mxsfb->base + mxsfb->devdata->next_buf); } static void mxsfb_plane_overlay_atomic_update(struct drm_plane *plane, @@ -557,11 +556,11 @@ static void mxsfb_plane_overlay_atomic_update(struct drm_plane *plane, struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(plane->dev); struct drm_plane_state *new_pstate = drm_atomic_get_new_plane_state(state, plane); - dma_addr_t paddr; + dma_addr_t dma_addr; u32 ctrl; - paddr = drm_fb_cma_get_gem_addr(new_pstate->fb, new_pstate, 0); - if (!paddr) { + dma_addr = drm_fb_dma_get_gem_addr(new_pstate->fb, new_pstate, 0); + if (!dma_addr) { writel(0, mxsfb->base + LCDC_AS_CTRL); return; } @@ -572,16 +571,16 @@ static void mxsfb_plane_overlay_atomic_update(struct drm_plane *plane, * is understood, live with the 16 initial invalid pixels on the first * line and start 64 bytes within the framebuffer. */ - paddr += 64; + dma_addr += 64; - writel(paddr, mxsfb->base + LCDC_AS_NEXT_BUF); + writel(dma_addr, mxsfb->base + LCDC_AS_NEXT_BUF); /* * If the plane was previously disabled, write LCDC_AS_BUF as well to * provide the first buffer. */ if (!old_pstate->fb) - writel(paddr, mxsfb->base + LCDC_AS_BUF); + writel(dma_addr, mxsfb->base + LCDC_AS_BUF); ctrl = AS_CTRL_AS_ENABLE | AS_CTRL_ALPHA(255); diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c index f9e962fd94d0..660c4cbc0b3d 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c @@ -1275,6 +1275,12 @@ static const uint32_t modeset_formats[] = { DRM_FORMAT_XRGB1555, }; +static const struct drm_plane_funcs nv04_primary_plane_funcs = { + .update_plane = drm_plane_helper_update_primary, + .disable_plane = drm_plane_helper_disable_primary, + .destroy = drm_plane_helper_destroy, +}; + static struct drm_plane * create_primary_plane(struct drm_device *dev) { @@ -1289,7 +1295,7 @@ create_primary_plane(struct drm_device *dev) /* possible_crtc's will be filled in later by crtc_init */ ret = drm_universal_plane_init(dev, primary, 0, - &drm_primary_helper_funcs, + &nv04_primary_plane_funcs, modeset_formats, ARRAY_SIZE(modeset_formats), NULL, DRM_PLANE_TYPE_PRIMARY, NULL); diff --git a/drivers/gpu/drm/nouveau/dispnv50/base507c.c b/drivers/gpu/drm/nouveau/dispnv50/base507c.c index cad5a646983a..70c62b861276 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/base507c.c +++ b/drivers/gpu/drm/nouveau/dispnv50/base507c.c @@ -29,7 +29,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_fourcc.h> -#include <drm/drm_plane_helper.h> #include "nouveau_bo.h" @@ -237,8 +236,8 @@ base507c_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, int ret; ret = drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, false, true); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/dispnv50/curs507a.c b/drivers/gpu/drm/nouveau/dispnv50/curs507a.c index cd2c79e4b7af..78ee32da01c8 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/curs507a.c +++ b/drivers/gpu/drm/nouveau/dispnv50/curs507a.c @@ -29,7 +29,6 @@ #include <nvhw/class/cl507a.h> #include <drm/drm_atomic_helper.h> -#include <drm/drm_plane_helper.h> bool curs507a_space(struct nv50_wndw *wndw) @@ -103,8 +102,8 @@ curs507a_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, int ret; ret = drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, true, true); asyh->curs.visible = asyw->state.visible; if (ret || !asyh->curs.visible) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index a53d685a77eb..c8fedd7d227f 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -39,7 +39,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_edid.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> diff --git a/drivers/gpu/drm/nouveau/dispnv50/ovly507e.c b/drivers/gpu/drm/nouveau/dispnv50/ovly507e.c index d4af69e903ad..797c1e4e0eaa 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/ovly507e.c +++ b/drivers/gpu/drm/nouveau/dispnv50/ovly507e.c @@ -24,7 +24,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_fourcc.h> -#include <drm/drm_plane_helper.h> #include <nvif/if0014.h> #include <nvif/push507c.h> @@ -106,8 +105,8 @@ ovly507e_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, int ret; ret = drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, true, true); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c b/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c index 082a66d59506..b3deea5aca58 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c +++ b/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c @@ -23,7 +23,6 @@ #include "atom.h" #include <drm/drm_atomic_helper.h> -#include <drm/drm_plane_helper.h> #include <nouveau_bo.h> #include <nvif/if0014.h> @@ -297,8 +296,8 @@ wndwc37e_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, struct nv50_head_atom *asyh) { return drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, true, true); } diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c b/drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c index 31167c398708..1d214a4b960a 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c +++ b/drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c @@ -23,7 +23,6 @@ #include "atom.h" #include <drm/drm_atomic_helper.h> -#include <drm/drm_plane_helper.h> #include <nouveau_bo.h> #include <nvif/pushc37b.h> diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 05076e530e7d..35bb0bb3fe61 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -281,8 +281,10 @@ nouveau_bo_alloc(struct nouveau_cli *cli, u64 *size, int *align, u32 domain, break; } - if (WARN_ON(pi < 0)) + if (WARN_ON(pi < 0)) { + kfree(nvbo); return ERR_PTR(-EINVAL); + } /* Disable compression if suitable settings couldn't be found. */ if (nvbo->comp && !vmm->page[pi].comp) { @@ -307,9 +309,9 @@ nouveau_bo_init(struct nouveau_bo *nvbo, u64 size, int align, u32 domain, nouveau_bo_placement_set(nvbo, domain, 0); INIT_LIST_HEAD(&nvbo->io_reserve_lru); - ret = ttm_bo_init(nvbo->bo.bdev, &nvbo->bo, size, type, - &nvbo->placement, align >> PAGE_SHIFT, false, sg, - robj, nouveau_bo_del_ttm); + ret = ttm_bo_init_validate(nvbo->bo.bdev, &nvbo->bo, type, + &nvbo->placement, align >> PAGE_SHIFT, false, + sg, robj, nouveau_bo_del_ttm); if (ret) { /* ttm will call nouveau_bo_del_ttm if it fails.. */ return ret; @@ -1006,7 +1008,8 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, } /* Fake bo copy. */ - if (old_reg->mem_type == TTM_PL_SYSTEM && !bo->ttm) { + if (!old_reg || (old_reg->mem_type == TTM_PL_SYSTEM && + !bo->ttm)) { ttm_bo_move_null(bo, new_reg); goto out; } diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 43a9d1e1cf71..8100c75ee731 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -504,7 +504,8 @@ nouveau_connector_set_encoder(struct drm_connector *connector, connector->interlace_allowed = nv_encoder->caps.dp_interlace; else - connector->interlace_allowed = true; + connector->interlace_allowed = + drm->client.device.info.family < NV_DEVICE_INFO_V0_VOLTA; connector->doublescan_allowed = true; } else if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS || diff --git a/drivers/gpu/drm/nouveau/nouveau_prime.c b/drivers/gpu/drm/nouveau/nouveau_prime.c index 347488685f74..9608121e49b7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_prime.c +++ b/drivers/gpu/drm/nouveau/nouveau_prime.c @@ -71,7 +71,6 @@ struct drm_gem_object *nouveau_gem_prime_import_sg_table(struct drm_device *dev, ret = nouveau_bo_init(nvbo, size, align, NOUVEAU_GEM_DOMAIN_GART, sg, robj); if (ret) { - nouveau_bo_ref(NULL, &nvbo); obj = ERR_PTR(ret); goto unlock; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c index b4a308f3cf7b..49e2664a734c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c @@ -64,12 +64,9 @@ nvbios_pmuEp(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr, struct nvbios_pmuE *info) { u32 data = nvbios_pmuEe(bios, idx, ver, hdr); - memset(info, 0x00, sizeof(*info)); - switch (!!data * *ver) { - default: + if (data) { info->type = nvbios_rd08(bios, data + 0x00); info->data = nvbios_rd32(bios, data + 0x02); - break; } return data; } diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 06a719c104f4..63ddc5127f7b 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -10,7 +10,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_mode.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_vblank.h> #include "omap_drv.h" diff --git a/drivers/gpu/drm/omapdrm/omap_overlay.c b/drivers/gpu/drm/omapdrm/omap_overlay.c index b0bc9ad2ef73..fb97c74386f2 100644 --- a/drivers/gpu/drm/omapdrm/omap_overlay.c +++ b/drivers/gpu/drm/omapdrm/omap_overlay.c @@ -6,7 +6,6 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> -#include <drm/drm_plane_helper.h> #include "omap_dmm_tiler.h" #include "omap_drv.h" diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index b6cb537f7689..24a2ded08b45 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -8,7 +8,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_blend.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index a9043eacce97..584a69f99af6 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -166,7 +166,7 @@ config DRM_PANEL_ILITEK_ILI9341 tristate "Ilitek ILI9341 240x320 QVGA panels" depends on OF && SPI depends on DRM_KMS_HELPER - depends on DRM_GEM_CMA_HELPER + depends on DRM_GEM_DMA_HELPER depends on BACKLIGHT_CLASS_DEVICE select DRM_MIPI_DBI help diff --git a/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c b/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c index 174ff434bd71..b3235781e6ba 100644 --- a/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c +++ b/drivers/gpu/drm/panel/panel-asus-z00t-tm5p5-n35596.c @@ -321,7 +321,7 @@ static int tm5p5_nt35596_probe(struct mipi_dsi_device *dsi) return 0; } -static int tm5p5_nt35596_remove(struct mipi_dsi_device *dsi) +static void tm5p5_nt35596_remove(struct mipi_dsi_device *dsi) { struct tm5p5_nt35596 *ctx = mipi_dsi_get_drvdata(dsi); int ret; @@ -332,8 +332,6 @@ static int tm5p5_nt35596_remove(struct mipi_dsi_device *dsi) "Failed to detach from DSI host: %d\n", ret); drm_panel_remove(&ctx->panel); - - return 0; } static const struct of_device_id tm5p5_nt35596_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-boe-bf060y8m-aj0.c b/drivers/gpu/drm/panel/panel-boe-bf060y8m-aj0.c index ef00cd67dc40..ad58840eda41 100644 --- a/drivers/gpu/drm/panel/panel-boe-bf060y8m-aj0.c +++ b/drivers/gpu/drm/panel/panel-boe-bf060y8m-aj0.c @@ -410,7 +410,7 @@ static int boe_bf060y8m_aj0_probe(struct mipi_dsi_device *dsi) return 0; } -static int boe_bf060y8m_aj0_remove(struct mipi_dsi_device *dsi) +static void boe_bf060y8m_aj0_remove(struct mipi_dsi_device *dsi) { struct boe_bf060y8m_aj0 *boe = mipi_dsi_get_drvdata(dsi); int ret; @@ -420,8 +420,6 @@ static int boe_bf060y8m_aj0_remove(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); drm_panel_remove(&boe->panel); - - return 0; } static const struct of_device_id boe_bf060y8m_aj0_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-boe-himax8279d.c b/drivers/gpu/drm/panel/panel-boe-himax8279d.c index 42854bd37fd5..d879b3b14c48 100644 --- a/drivers/gpu/drm/panel/panel-boe-himax8279d.c +++ b/drivers/gpu/drm/panel/panel-boe-himax8279d.c @@ -919,7 +919,7 @@ static int panel_probe(struct mipi_dsi_device *dsi) return err; } -static int panel_remove(struct mipi_dsi_device *dsi) +static void panel_remove(struct mipi_dsi_device *dsi) { struct panel_info *pinfo = mipi_dsi_get_drvdata(dsi); int err; @@ -937,8 +937,6 @@ static int panel_remove(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); drm_panel_remove(&pinfo->base); - - return 0; } static void panel_shutdown(struct mipi_dsi_device *dsi) diff --git a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c index 07f722f33fc5..857a2f0420d7 100644 --- a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c +++ b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c @@ -1622,7 +1622,7 @@ static void boe_panel_shutdown(struct mipi_dsi_device *dsi) drm_panel_unprepare(&boe->base); } -static int boe_panel_remove(struct mipi_dsi_device *dsi) +static void boe_panel_remove(struct mipi_dsi_device *dsi) { struct boe_panel *boe = mipi_dsi_get_drvdata(dsi); int ret; @@ -1635,8 +1635,6 @@ static int boe_panel_remove(struct mipi_dsi_device *dsi) if (boe->base.dev) drm_panel_remove(&boe->base); - - return 0; } static const struct of_device_id boe_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-dsi-cm.c b/drivers/gpu/drm/panel/panel-dsi-cm.c index b0213a518f9d..ba17bcc4461c 100644 --- a/drivers/gpu/drm/panel/panel-dsi-cm.c +++ b/drivers/gpu/drm/panel/panel-dsi-cm.c @@ -579,7 +579,7 @@ err_bl: return r; } -static int dsicm_remove(struct mipi_dsi_device *dsi) +static void dsicm_remove(struct mipi_dsi_device *dsi) { struct panel_drv_data *ddata = mipi_dsi_get_drvdata(dsi); @@ -593,8 +593,6 @@ static int dsicm_remove(struct mipi_dsi_device *dsi) if (ddata->extbldev) put_device(&ddata->extbldev->dev); - - return 0; } static const struct dsic_panel_data taal_data = { diff --git a/drivers/gpu/drm/panel/panel-ebbg-ft8719.c b/drivers/gpu/drm/panel/panel-ebbg-ft8719.c index 386f8321b930..e85d63a176d0 100644 --- a/drivers/gpu/drm/panel/panel-ebbg-ft8719.c +++ b/drivers/gpu/drm/panel/panel-ebbg-ft8719.c @@ -250,7 +250,7 @@ static int ebbg_ft8719_probe(struct mipi_dsi_device *dsi) return 0; } -static int ebbg_ft8719_remove(struct mipi_dsi_device *dsi) +static void ebbg_ft8719_remove(struct mipi_dsi_device *dsi) { struct ebbg_ft8719 *ctx = mipi_dsi_get_drvdata(dsi); int ret; @@ -260,8 +260,6 @@ static int ebbg_ft8719_remove(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); drm_panel_remove(&ctx->panel); - - return 0; } static const struct of_device_id ebbg_ft8719_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index cdb154c8b866..335153bb76e2 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -1854,6 +1854,12 @@ static const struct panel_delay delay_100_500_e200 = { .enable = 200, }; +static const struct panel_delay delay_200_500_e200 = { + .hpd_absent = 200, + .unprepare = 500, + .enable = 200, +}; + #define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _delay, _name) \ { \ .name = _name, \ @@ -1870,6 +1876,7 @@ static const struct panel_delay delay_100_500_e200 = { * Sort first by vendor, then by product ID. */ static const struct edp_panel_entry edp_panels[] = { + EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, "B120XAN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"), @@ -1882,6 +1889,8 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('C', 'M', 'N', 0x114c, &innolux_n116bca_ea1.delay, "N116BCA-EA1"), + EDP_PANEL_ENTRY('I', 'V', 'O', 0x057d, &delay_200_500_e200, "R140NWF5 RH"), + EDP_PANEL_ENTRY('K', 'D', 'B', 0x0624, &kingdisplay_kd116n21_30nv_a010.delay, "116N21-30NV-A010"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x1120, &delay_200_500_e80_d50, "116N29-30NK-C007"), diff --git a/drivers/gpu/drm/panel/panel-elida-kd35t133.c b/drivers/gpu/drm/panel/panel-elida-kd35t133.c index 01dd555a7f26..eee714cf3f49 100644 --- a/drivers/gpu/drm/panel/panel-elida-kd35t133.c +++ b/drivers/gpu/drm/panel/panel-elida-kd35t133.c @@ -321,7 +321,7 @@ static void kd35t133_shutdown(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); } -static int kd35t133_remove(struct mipi_dsi_device *dsi) +static void kd35t133_remove(struct mipi_dsi_device *dsi) { struct kd35t133 *ctx = mipi_dsi_get_drvdata(dsi); int ret; @@ -333,8 +333,6 @@ static int kd35t133_remove(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); drm_panel_remove(&ctx->panel); - - return 0; } static const struct of_device_id kd35t133_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c b/drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c index cb0bb3076099..76572c922983 100644 --- a/drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c +++ b/drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c @@ -486,14 +486,12 @@ static int k101_im2ba02_dsi_probe(struct mipi_dsi_device *dsi) return 0; } -static int k101_im2ba02_dsi_remove(struct mipi_dsi_device *dsi) +static void k101_im2ba02_dsi_remove(struct mipi_dsi_device *dsi) { struct k101_im2ba02 *ctx = mipi_dsi_get_drvdata(dsi); mipi_dsi_detach(dsi); drm_panel_remove(&ctx->panel); - - return 0; } static const struct of_device_id k101_im2ba02_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c b/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c index ee61d60eceae..df493da50afe 100644 --- a/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c +++ b/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c @@ -233,14 +233,12 @@ static int feiyang_dsi_probe(struct mipi_dsi_device *dsi) return 0; } -static int feiyang_dsi_remove(struct mipi_dsi_device *dsi) +static void feiyang_dsi_remove(struct mipi_dsi_device *dsi) { struct feiyang *ctx = mipi_dsi_get_drvdata(dsi); mipi_dsi_detach(dsi); drm_panel_remove(&ctx->panel); - - return 0; } static const struct of_device_id feiyang_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9341.c b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c index 6826f4d4826a..7da09e34385d 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9341.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c @@ -32,7 +32,7 @@ #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_mipi_dbi.h> #include <drm/drm_modes.h> @@ -586,12 +586,12 @@ static const struct drm_display_mode ili9341_dbi_mode = { DRM_SIMPLE_MODE(240, 320, 37, 49), }; -DEFINE_DRM_GEM_CMA_FOPS(ili9341_dbi_fops); +DEFINE_DRM_GEM_DMA_FOPS(ili9341_dbi_fops); static struct drm_driver ili9341_dbi_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .fops = &ili9341_dbi_fops, - DRM_GEM_CMA_DRIVER_OPS_VMAP, + DRM_GEM_DMA_DRIVER_OPS_VMAP, .debugfs_init = mipi_dbi_debugfs_init, .name = "ili9341", .desc = "Ilitek ILI9341", diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c index 596861269774..cbb68caa36f2 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c @@ -923,14 +923,12 @@ static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi) return mipi_dsi_attach(dsi); } -static int ili9881c_dsi_remove(struct mipi_dsi_device *dsi) +static void ili9881c_dsi_remove(struct mipi_dsi_device *dsi) { struct ili9881c *ctx = mipi_dsi_get_drvdata(dsi); mipi_dsi_detach(dsi); drm_panel_remove(&ctx->panel); - - return 0; } static const struct ili9881c_desc lhr050h41_desc = { diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index f194b62e290c..9992d0d4c0e5 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -506,7 +506,7 @@ static int innolux_panel_probe(struct mipi_dsi_device *dsi) return 0; } -static int innolux_panel_remove(struct mipi_dsi_device *dsi) +static void innolux_panel_remove(struct mipi_dsi_device *dsi) { struct innolux_panel *innolux = mipi_dsi_get_drvdata(dsi); int err; @@ -524,8 +524,6 @@ static int innolux_panel_remove(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); innolux_panel_del(innolux); - - return 0; } static void innolux_panel_shutdown(struct mipi_dsi_device *dsi) diff --git a/drivers/gpu/drm/panel/panel-jdi-fhd-r63452.c b/drivers/gpu/drm/panel/panel-jdi-fhd-r63452.c index 31eafbc38ec0..d8765b2294fb 100644 --- a/drivers/gpu/drm/panel/panel-jdi-fhd-r63452.c +++ b/drivers/gpu/drm/panel/panel-jdi-fhd-r63452.c @@ -288,7 +288,7 @@ static int jdi_fhd_r63452_probe(struct mipi_dsi_device *dsi) return 0; } -static int jdi_fhd_r63452_remove(struct mipi_dsi_device *dsi) +static void jdi_fhd_r63452_remove(struct mipi_dsi_device *dsi) { struct jdi_fhd_r63452 *ctx = mipi_dsi_get_drvdata(dsi); int ret; @@ -298,8 +298,6 @@ static int jdi_fhd_r63452_remove(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); drm_panel_remove(&ctx->panel); - - return 0; } static const struct of_device_id jdi_fhd_r63452_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c index 3c86ad262d5e..8f4f137a2af6 100644 --- a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c +++ b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c @@ -482,7 +482,7 @@ static int jdi_panel_probe(struct mipi_dsi_device *dsi) return 0; } -static int jdi_panel_remove(struct mipi_dsi_device *dsi) +static void jdi_panel_remove(struct mipi_dsi_device *dsi) { struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi); int ret; @@ -497,8 +497,6 @@ static int jdi_panel_remove(struct mipi_dsi_device *dsi) ret); jdi_panel_del(jdi); - - return 0; } static void jdi_panel_shutdown(struct mipi_dsi_device *dsi) diff --git a/drivers/gpu/drm/panel/panel-khadas-ts050.c b/drivers/gpu/drm/panel/panel-khadas-ts050.c index a3ec4cbdbf7a..1ab1ebe30882 100644 --- a/drivers/gpu/drm/panel/panel-khadas-ts050.c +++ b/drivers/gpu/drm/panel/panel-khadas-ts050.c @@ -830,7 +830,7 @@ static int khadas_ts050_panel_probe(struct mipi_dsi_device *dsi) return err; } -static int khadas_ts050_panel_remove(struct mipi_dsi_device *dsi) +static void khadas_ts050_panel_remove(struct mipi_dsi_device *dsi) { struct khadas_ts050_panel *khadas_ts050 = mipi_dsi_get_drvdata(dsi); int err; @@ -842,8 +842,6 @@ static int khadas_ts050_panel_remove(struct mipi_dsi_device *dsi) drm_panel_remove(&khadas_ts050->base); drm_panel_disable(&khadas_ts050->base); drm_panel_unprepare(&khadas_ts050->base); - - return 0; } static void khadas_ts050_panel_shutdown(struct mipi_dsi_device *dsi) diff --git a/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c b/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c index daccb1fd5fda..17f8d80cf2b3 100644 --- a/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c +++ b/drivers/gpu/drm/panel/panel-kingdisplay-kd097d04.c @@ -415,7 +415,7 @@ static int kingdisplay_panel_probe(struct mipi_dsi_device *dsi) return 0; } -static int kingdisplay_panel_remove(struct mipi_dsi_device *dsi) +static void kingdisplay_panel_remove(struct mipi_dsi_device *dsi) { struct kingdisplay_panel *kingdisplay = mipi_dsi_get_drvdata(dsi); int err; @@ -433,8 +433,6 @@ static int kingdisplay_panel_remove(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); kingdisplay_panel_del(kingdisplay); - - return 0; } static void kingdisplay_panel_shutdown(struct mipi_dsi_device *dsi) diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c index a5a414920430..5619f186d28c 100644 --- a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c +++ b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c @@ -628,7 +628,7 @@ static void ltk050h3146w_shutdown(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); } -static int ltk050h3146w_remove(struct mipi_dsi_device *dsi) +static void ltk050h3146w_remove(struct mipi_dsi_device *dsi) { struct ltk050h3146w *ctx = mipi_dsi_get_drvdata(dsi); int ret; @@ -640,8 +640,6 @@ static int ltk050h3146w_remove(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); drm_panel_remove(&ctx->panel); - - return 0; } static const struct of_device_id ltk050h3146w_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c b/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c index 21e48923836d..39e408c9f762 100644 --- a/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c +++ b/drivers/gpu/drm/panel/panel-leadtek-ltk500hd1829.c @@ -477,7 +477,7 @@ static void ltk500hd1829_shutdown(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); } -static int ltk500hd1829_remove(struct mipi_dsi_device *dsi) +static void ltk500hd1829_remove(struct mipi_dsi_device *dsi) { struct ltk500hd1829 *ctx = mipi_dsi_get_drvdata(dsi); int ret; @@ -489,8 +489,6 @@ static int ltk500hd1829_remove(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret); drm_panel_remove(&ctx->panel); - - return 0; } static const struct of_device_id ltk500hd1829_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c b/drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c index 31daae1da9c9..772e3b6acece 100644 --- a/drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c +++ b/drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c @@ -336,7 +336,7 @@ static void mantix_shutdown(struct mipi_dsi_device *dsi) drm_panel_disable(&ctx->panel); } -static int mantix_remove(struct mipi_dsi_device *dsi) +static void mantix_remove(struct mipi_dsi_device *dsi) { struct mantix *ctx = mipi_dsi_get_drvdata(dsi); @@ -344,8 +344,6 @@ static int mantix_remove(struct mipi_dsi_device *dsi) mipi_dsi_detach(dsi); drm_panel_remove(&ctx->panel); - - return 0; } static const struct of_device_id mantix_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35510.c b/drivers/gpu/drm/panel/panel-novatek-nt35510.c index 40ea41b0a5dd..493c3c23f0d6 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt35510.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt35510.c @@ -231,7 +231,7 @@ struct nt35510_config { * bits 0..2 in the lower nibble controls HCK, the booster clock * frequency, the values are the same as for PCK in @bt1ctr. * bits 4..5 in the upper nibble controls BTH, the boosting - * amplification for the the step-up circuit. + * amplification for the step-up circuit. * 0 = AVDD + VDDB * 1 = AVDD - AVEE * 2 = AVDD - AVEE + VDDB @@ -966,7 +966,7 @@ static int nt35510_probe(struct mipi_dsi_device *dsi) return 0; } -static int nt35510_remove(struct mipi_dsi_device *dsi) +static void nt35510_remove(struct mipi_dsi_device *dsi) { struct nt35510 *nt = mipi_dsi_get_drvdata(dsi); int ret; @@ -974,9 +974,10 @@ static int nt35510_remove(struct mipi_dsi_device *dsi) mipi_dsi_detach(dsi); /* Power off */ ret = nt35510_power_off(nt); - drm_panel_remove(&nt->panel); + if (ret) + dev_err(&dsi->dev, "Failed to power off\n"); - return ret; + drm_panel_remove(&nt->panel); } /* diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35560.c b/drivers/gpu/drm/panel/panel-novatek-nt35560.c index 1b6042321ea1..cc7f96d70826 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt35560.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt35560.c @@ -523,14 +523,12 @@ static int nt35560_probe(struct mipi_dsi_device *dsi) return 0; } -static int nt35560_remove(struct mipi_dsi_device *dsi) +static void nt35560_remove(struct mipi_dsi_device *dsi) { struct nt35560 *nt = mipi_dsi_get_drvdata(dsi); mipi_dsi_detach(dsi); drm_panel_remove(&nt->panel); - - return 0; } static const struct of_device_id nt35560_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35950.c b/drivers/gpu/drm/panel/panel-novatek-nt35950.c index 288c7fa83ecc..3a844917da07 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt35950.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt35950.c @@ -620,7 +620,7 @@ static int nt35950_probe(struct mipi_dsi_device *dsi) return 0; } -static int nt35950_remove(struct mipi_dsi_device *dsi) +static void nt35950_remove(struct mipi_dsi_device *dsi) { struct nt35950 *nt = mipi_dsi_get_drvdata(dsi); int ret; @@ -639,8 +639,6 @@ static int nt35950_remove(struct mipi_dsi_device *dsi) } drm_panel_remove(&nt->panel); - - return 0; } static const struct nt35950_panel_mode sharp_ls055d1sx04_modes[] = { diff --git a/drivers/gpu/drm/panel/panel-novatek-nt36672a.c b/drivers/gpu/drm/panel/panel-novatek-nt36672a.c index 6d6ce42787e2..73bcffa1e0c1 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt36672a.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt36672a.c @@ -669,7 +669,7 @@ static int nt36672a_panel_probe(struct mipi_dsi_device *dsi) return 0; } -static int nt36672a_panel_remove(struct mipi_dsi_device *dsi) +static void nt36672a_panel_remove(struct mipi_dsi_device *dsi) { struct nt36672a_panel *pinfo = mipi_dsi_get_drvdata(dsi); int err; @@ -687,8 +687,6 @@ static int nt36672a_panel_remove(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); drm_panel_remove(&pinfo->base); - - return 0; } static void nt36672a_panel_shutdown(struct mipi_dsi_device *dsi) diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c index dfb43b1374e7..b4729a94c34a 100644 --- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c +++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c @@ -497,14 +497,12 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi) return 0; } -static int otm8009a_remove(struct mipi_dsi_device *dsi) +static void otm8009a_remove(struct mipi_dsi_device *dsi) { struct otm8009a *ctx = mipi_dsi_get_drvdata(dsi); mipi_dsi_detach(dsi); drm_panel_remove(&ctx->panel); - - return 0; } static const struct of_device_id orisetech_otm8009a_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c b/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c index 198493a6eb6a..493e0504f6f7 100644 --- a/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c +++ b/drivers/gpu/drm/panel/panel-osd-osd101t2587-53ts.c @@ -206,7 +206,7 @@ static int osd101t2587_panel_probe(struct mipi_dsi_device *dsi) return ret; } -static int osd101t2587_panel_remove(struct mipi_dsi_device *dsi) +static void osd101t2587_panel_remove(struct mipi_dsi_device *dsi) { struct osd101t2587_panel *osd101t2587 = mipi_dsi_get_drvdata(dsi); int ret; @@ -221,8 +221,6 @@ static int osd101t2587_panel_remove(struct mipi_dsi_device *dsi) ret = mipi_dsi_detach(dsi); if (ret < 0) dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret); - - return ret; } static void osd101t2587_panel_shutdown(struct mipi_dsi_device *dsi) diff --git a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c index 3991f5d950af..8ba6d8287938 100644 --- a/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c +++ b/drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c @@ -250,7 +250,7 @@ static int wuxga_nt_panel_probe(struct mipi_dsi_device *dsi) return 0; } -static int wuxga_nt_panel_remove(struct mipi_dsi_device *dsi) +static void wuxga_nt_panel_remove(struct mipi_dsi_device *dsi) { struct wuxga_nt_panel *wuxga_nt = mipi_dsi_get_drvdata(dsi); int ret; @@ -264,8 +264,6 @@ static int wuxga_nt_panel_remove(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret); wuxga_nt_panel_del(wuxga_nt); - - return 0; } static void wuxga_nt_panel_shutdown(struct mipi_dsi_device *dsi) diff --git a/drivers/gpu/drm/panel/panel-raydium-rm67191.c b/drivers/gpu/drm/panel/panel-raydium-rm67191.c index 4e021a572211..dbb1ed4efbed 100644 --- a/drivers/gpu/drm/panel/panel-raydium-rm67191.c +++ b/drivers/gpu/drm/panel/panel-raydium-rm67191.c @@ -616,7 +616,7 @@ static int rad_panel_probe(struct mipi_dsi_device *dsi) return ret; } -static int rad_panel_remove(struct mipi_dsi_device *dsi) +static void rad_panel_remove(struct mipi_dsi_device *dsi) { struct rad_panel *rad = mipi_dsi_get_drvdata(dsi); struct device *dev = &dsi->dev; @@ -627,8 +627,6 @@ static int rad_panel_remove(struct mipi_dsi_device *dsi) dev_err(dev, "Failed to detach from host (%d)\n", ret); drm_panel_remove(&rad->panel); - - return 0; } static void rad_panel_shutdown(struct mipi_dsi_device *dsi) diff --git a/drivers/gpu/drm/panel/panel-raydium-rm68200.c b/drivers/gpu/drm/panel/panel-raydium-rm68200.c index 412c0dbcb2b6..5f9b340588fb 100644 --- a/drivers/gpu/drm/panel/panel-raydium-rm68200.c +++ b/drivers/gpu/drm/panel/panel-raydium-rm68200.c @@ -412,14 +412,12 @@ static int rm68200_probe(struct mipi_dsi_device *dsi) return 0; } -static int rm68200_remove(struct mipi_dsi_device *dsi) +static void rm68200_remove(struct mipi_dsi_device *dsi) { struct rm68200 *ctx = mipi_dsi_get_drvdata(dsi); mipi_dsi_detach(dsi); drm_panel_remove(&ctx->panel); - - return 0; } static const struct of_device_id raydium_rm68200_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c b/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c index 1fb579a574d9..a8a98c91b13c 100644 --- a/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c +++ b/drivers/gpu/drm/panel/panel-ronbo-rb070d30.c @@ -208,14 +208,12 @@ static int rb070d30_panel_dsi_probe(struct mipi_dsi_device *dsi) return 0; } -static int rb070d30_panel_dsi_remove(struct mipi_dsi_device *dsi) +static void rb070d30_panel_dsi_remove(struct mipi_dsi_device *dsi) { struct rb070d30_panel *ctx = mipi_dsi_get_drvdata(dsi); mipi_dsi_detach(dsi); drm_panel_remove(&ctx->panel); - - return 0; } static const struct of_device_id rb070d30_panel_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c index 70560cac53a9..008e2b0d6652 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c @@ -212,14 +212,12 @@ static int s6d16d0_probe(struct mipi_dsi_device *dsi) return ret; } -static int s6d16d0_remove(struct mipi_dsi_device *dsi) +static void s6d16d0_remove(struct mipi_dsi_device *dsi) { struct s6d16d0 *s6 = mipi_dsi_get_drvdata(dsi); mipi_dsi_detach(dsi); drm_panel_remove(&s6->panel); - - return 0; } static const struct of_device_id s6d16d0_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c b/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c index 0ab1b7ec84cd..5c621b15e84c 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c @@ -747,15 +747,13 @@ remove_panel: return ret; } -static int s6e3ha2_remove(struct mipi_dsi_device *dsi) +static void s6e3ha2_remove(struct mipi_dsi_device *dsi) { struct s6e3ha2 *ctx = mipi_dsi_get_drvdata(dsi); mipi_dsi_detach(dsi); drm_panel_remove(&ctx->panel); backlight_device_unregister(ctx->bl_dev); - - return 0; } static const struct of_device_id s6e3ha2_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c b/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c index e38262b67ff7..e06fd35de814 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c @@ -488,7 +488,7 @@ remove_panel: return ret; } -static int s6e63j0x03_remove(struct mipi_dsi_device *dsi) +static void s6e63j0x03_remove(struct mipi_dsi_device *dsi) { struct s6e63j0x03 *ctx = mipi_dsi_get_drvdata(dsi); @@ -496,8 +496,6 @@ static int s6e63j0x03_remove(struct mipi_dsi_device *dsi) drm_panel_remove(&ctx->panel); backlight_device_unregister(ctx->bl_dev); - - return 0; } static const struct of_device_id s6e63j0x03_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63m0-dsi.c b/drivers/gpu/drm/panel/panel-samsung-s6e63m0-dsi.c index e0f773678168..ed3895e4ca5e 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e63m0-dsi.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63m0-dsi.c @@ -113,11 +113,10 @@ static int s6e63m0_dsi_probe(struct mipi_dsi_device *dsi) return ret; } -static int s6e63m0_dsi_remove(struct mipi_dsi_device *dsi) +static void s6e63m0_dsi_remove(struct mipi_dsi_device *dsi) { mipi_dsi_detach(dsi); s6e63m0_remove(&dsi->dev); - return 0; } static const struct of_device_id s6e63m0_dsi_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c b/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c index 29fde3823212..97ff7a18545c 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams452ef01.c @@ -254,7 +254,7 @@ static int s6e88a0_ams452ef01_probe(struct mipi_dsi_device *dsi) return 0; } -static int s6e88a0_ams452ef01_remove(struct mipi_dsi_device *dsi) +static void s6e88a0_ams452ef01_remove(struct mipi_dsi_device *dsi) { struct s6e88a0_ams452ef01 *ctx = mipi_dsi_get_drvdata(dsi); int ret; @@ -264,8 +264,6 @@ static int s6e88a0_ams452ef01_remove(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); drm_panel_remove(&ctx->panel); - - return 0; } static const struct of_device_id s6e88a0_ams452ef01_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c index 9b3599d6d2de..54213beafaf5 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c @@ -1028,14 +1028,12 @@ static int s6e8aa0_probe(struct mipi_dsi_device *dsi) return ret; } -static int s6e8aa0_remove(struct mipi_dsi_device *dsi) +static void s6e8aa0_remove(struct mipi_dsi_device *dsi) { struct s6e8aa0 *ctx = mipi_dsi_get_drvdata(dsi); mipi_dsi_detach(dsi); drm_panel_remove(&ctx->panel); - - return 0; } static const struct of_device_id s6e8aa0_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-samsung-sofef00.c b/drivers/gpu/drm/panel/panel-samsung-sofef00.c index 1fb37fda4ba9..1a0d24595faa 100644 --- a/drivers/gpu/drm/panel/panel-samsung-sofef00.c +++ b/drivers/gpu/drm/panel/panel-samsung-sofef00.c @@ -305,7 +305,7 @@ static int sofef00_panel_probe(struct mipi_dsi_device *dsi) return 0; } -static int sofef00_panel_remove(struct mipi_dsi_device *dsi) +static void sofef00_panel_remove(struct mipi_dsi_device *dsi) { struct sofef00_panel *ctx = mipi_dsi_get_drvdata(dsi); int ret; @@ -315,8 +315,6 @@ static int sofef00_panel_remove(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); drm_panel_remove(&ctx->panel); - - return 0; } static const struct of_device_id sofef00_panel_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c index f8cd2a42ed13..14851408a5e1 100644 --- a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c +++ b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c @@ -391,7 +391,7 @@ static int sharp_panel_probe(struct mipi_dsi_device *dsi) return 0; } -static int sharp_panel_remove(struct mipi_dsi_device *dsi) +static void sharp_panel_remove(struct mipi_dsi_device *dsi) { struct sharp_panel *sharp = mipi_dsi_get_drvdata(dsi); int err; @@ -399,7 +399,7 @@ static int sharp_panel_remove(struct mipi_dsi_device *dsi) /* only detach from host for the DSI-LINK2 interface */ if (!sharp) { mipi_dsi_detach(dsi); - return 0; + return; } err = drm_panel_disable(&sharp->base); @@ -411,8 +411,6 @@ static int sharp_panel_remove(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); sharp_panel_del(sharp); - - return 0; } static void sharp_panel_shutdown(struct mipi_dsi_device *dsi) diff --git a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c index 25829a0a8e80..d1ec80a3e3c7 100644 --- a/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c +++ b/drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c @@ -305,7 +305,7 @@ static int sharp_nt_panel_probe(struct mipi_dsi_device *dsi) return 0; } -static int sharp_nt_panel_remove(struct mipi_dsi_device *dsi) +static void sharp_nt_panel_remove(struct mipi_dsi_device *dsi) { struct sharp_nt_panel *sharp_nt = mipi_dsi_get_drvdata(dsi); int ret; @@ -319,8 +319,6 @@ static int sharp_nt_panel_remove(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret); sharp_nt_panel_del(sharp_nt); - - return 0; } static void sharp_nt_panel_shutdown(struct mipi_dsi_device *dsi) diff --git a/drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c b/drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c index e12570561629..8a4e0c1fe73f 100644 --- a/drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c +++ b/drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c @@ -298,7 +298,7 @@ static int sharp_ls060_probe(struct mipi_dsi_device *dsi) return 0; } -static int sharp_ls060_remove(struct mipi_dsi_device *dsi) +static void sharp_ls060_remove(struct mipi_dsi_device *dsi) { struct sharp_ls060 *ctx = mipi_dsi_get_drvdata(dsi); int ret; @@ -308,8 +308,6 @@ static int sharp_ls060_remove(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); drm_panel_remove(&ctx->panel); - - return 0; } static const struct of_device_id sharp_ls060t1sx01_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index ff5e1a44c43a..edd5a0c35437 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -696,7 +696,7 @@ free_ddc: return err; } -static int panel_simple_remove(struct device *dev) +static void panel_simple_remove(struct device *dev) { struct panel_simple *panel = dev_get_drvdata(dev); @@ -708,8 +708,6 @@ static int panel_simple_remove(struct device *dev) pm_runtime_disable(dev); if (panel->ddc) put_device(&panel->ddc->dev); - - return 0; } static void panel_simple_shutdown(struct device *dev) @@ -3220,6 +3218,37 @@ static const struct panel_desc rocktech_rk101ii01d_ct = { .connector_type = DRM_MODE_CONNECTOR_LVDS, }; +static const struct display_timing samsung_ltl101al01_timing = { + .pixelclock = { 66663000, 66663000, 66663000 }, + .hactive = { 1280, 1280, 1280 }, + .hfront_porch = { 18, 18, 18 }, + .hback_porch = { 36, 36, 36 }, + .hsync_len = { 16, 16, 16 }, + .vactive = { 800, 800, 800 }, + .vfront_porch = { 4, 4, 4 }, + .vback_porch = { 16, 16, 16 }, + .vsync_len = { 3, 3, 3 }, + .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW, +}; + +static const struct panel_desc samsung_ltl101al01 = { + .timings = &samsung_ltl101al01_timing, + .num_timings = 1, + .bpc = 8, + .size = { + .width = 217, + .height = 135, + }, + .delay = { + .prepare = 40, + .enable = 300, + .disable = 200, + .unprepare = 600, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .connector_type = DRM_MODE_CONNECTOR_LVDS, +}; + static const struct drm_display_mode samsung_ltn101nt05_mode = { .clock = 54030, .hdisplay = 1024, @@ -4164,6 +4193,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "rocktech,rk101ii01d-ct", .data = &rocktech_rk101ii01d_ct, }, { + .compatible = "samsung,ltl101al01", + .data = &samsung_ltl101al01, + }, { .compatible = "samsung,ltn101nt05", .data = &samsung_ltn101nt05, }, { @@ -4273,7 +4305,9 @@ static int panel_simple_platform_probe(struct platform_device *pdev) static int panel_simple_platform_remove(struct platform_device *pdev) { - return panel_simple_remove(&pdev->dev); + panel_simple_remove(&pdev->dev); + + return 0; } static void panel_simple_platform_shutdown(struct platform_device *pdev) @@ -4566,7 +4600,7 @@ static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi) return err; } -static int panel_simple_dsi_remove(struct mipi_dsi_device *dsi) +static void panel_simple_dsi_remove(struct mipi_dsi_device *dsi) { int err; @@ -4574,7 +4608,7 @@ static int panel_simple_dsi_remove(struct mipi_dsi_device *dsi) if (err < 0) dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); - return panel_simple_remove(&dsi->dev); + panel_simple_remove(&dsi->dev); } static void panel_simple_dsi_shutdown(struct mipi_dsi_device *dsi) diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7701.c b/drivers/gpu/drm/panel/panel-sitronix-st7701.c index 320a2a8fd459..c481daa4bbce 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7701.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7701.c @@ -8,6 +8,7 @@ #include <drm/drm_modes.h> #include <drm/drm_panel.h> +#include <linux/bitfield.h> #include <linux/gpio/consumer.h> #include <linux/delay.h> #include <linux/module.h> @@ -41,59 +42,101 @@ /* * Command2 with BK function selection. * - * BIT[4, 0]: [CN2, BKXSEL] - * 10 = CMD2BK0, Command2 BK0 - * 11 = CMD2BK1, Command2 BK1 - * 00 = Command2 disable + * BIT[4].....CN2 + * BIT[1:0]...BKXSEL + * 1:00 = CMD2BK0, Command2 BK0 + * 1:01 = CMD2BK1, Command2 BK1 + * 1:11 = CMD2BK3, Command2 BK3 + * 0:00 = Command2 disable */ -#define DSI_CMD2BK1_SEL 0x11 #define DSI_CMD2BK0_SEL 0x10 +#define DSI_CMD2BK1_SEL 0x11 +#define DSI_CMD2BK3_SEL 0x13 #define DSI_CMD2BKX_SEL_NONE 0x00 /* Command2, BK0 bytes */ -#define DSI_LINESET_LINE 0x69 -#define DSI_LINESET_LDE_EN BIT(7) -#define DSI_LINESET_LINEDELTA GENMASK(1, 0) -#define DSI_CMD2_BK0_LNESET_B1 DSI_LINESET_LINEDELTA -#define DSI_CMD2_BK0_LNESET_B0 (DSI_LINESET_LDE_EN | DSI_LINESET_LINE) -#define DSI_INVSEL_DEFAULT GENMASK(5, 4) -#define DSI_INVSEL_NLINV GENMASK(2, 0) -#define DSI_INVSEL_RTNI GENMASK(2, 1) -#define DSI_CMD2_BK0_INVSEL_B1 DSI_INVSEL_RTNI -#define DSI_CMD2_BK0_INVSEL_B0 (DSI_INVSEL_DEFAULT | DSI_INVSEL_NLINV) -#define DSI_CMD2_BK0_PORCTRL_B0(m) ((m)->vtotal - (m)->vsync_end) -#define DSI_CMD2_BK0_PORCTRL_B1(m) ((m)->vsync_start - (m)->vdisplay) +#define DSI_CMD2_BK0_GAMCTRL_AJ_MASK GENMASK(7, 6) +#define DSI_CMD2_BK0_GAMCTRL_VC0_MASK GENMASK(3, 0) +#define DSI_CMD2_BK0_GAMCTRL_VC4_MASK GENMASK(5, 0) +#define DSI_CMD2_BK0_GAMCTRL_VC8_MASK GENMASK(5, 0) +#define DSI_CMD2_BK0_GAMCTRL_VC16_MASK GENMASK(4, 0) +#define DSI_CMD2_BK0_GAMCTRL_VC24_MASK GENMASK(4, 0) +#define DSI_CMD2_BK0_GAMCTRL_VC52_MASK GENMASK(3, 0) +#define DSI_CMD2_BK0_GAMCTRL_VC80_MASK GENMASK(5, 0) +#define DSI_CMD2_BK0_GAMCTRL_VC108_MASK GENMASK(3, 0) +#define DSI_CMD2_BK0_GAMCTRL_VC147_MASK GENMASK(3, 0) +#define DSI_CMD2_BK0_GAMCTRL_VC175_MASK GENMASK(5, 0) +#define DSI_CMD2_BK0_GAMCTRL_VC203_MASK GENMASK(3, 0) +#define DSI_CMD2_BK0_GAMCTRL_VC231_MASK GENMASK(4, 0) +#define DSI_CMD2_BK0_GAMCTRL_VC239_MASK GENMASK(4, 0) +#define DSI_CMD2_BK0_GAMCTRL_VC247_MASK GENMASK(5, 0) +#define DSI_CMD2_BK0_GAMCTRL_VC251_MASK GENMASK(5, 0) +#define DSI_CMD2_BK0_GAMCTRL_VC255_MASK GENMASK(4, 0) +#define DSI_CMD2_BK0_LNESET_LINE_MASK GENMASK(6, 0) +#define DSI_CMD2_BK0_LNESET_LDE_EN BIT(7) +#define DSI_CMD2_BK0_LNESET_LINEDELTA GENMASK(1, 0) +#define DSI_CMD2_BK0_PORCTRL_VBP_MASK GENMASK(7, 0) +#define DSI_CMD2_BK0_PORCTRL_VFP_MASK GENMASK(7, 0) +#define DSI_CMD2_BK0_INVSEL_ONES_MASK GENMASK(5, 4) +#define DSI_CMD2_BK0_INVSEL_NLINV_MASK GENMASK(2, 0) +#define DSI_CMD2_BK0_INVSEL_RTNI_MASK GENMASK(4, 0) /* Command2, BK1 bytes */ -#define DSI_CMD2_BK1_VRHA_SET 0x45 -#define DSI_CMD2_BK1_VCOM_SET 0x13 -#define DSI_CMD2_BK1_VGHSS_SET GENMASK(2, 0) +#define DSI_CMD2_BK1_VRHA_MASK GENMASK(7, 0) +#define DSI_CMD2_BK1_VCOM_MASK GENMASK(7, 0) +#define DSI_CMD2_BK1_VGHSS_MASK GENMASK(3, 0) #define DSI_CMD2_BK1_TESTCMD_VAL BIT(7) -#define DSI_VGLS_DEFAULT BIT(6) -#define DSI_VGLS_SEL GENMASK(2, 0) -#define DSI_CMD2_BK1_VGLS_SET (DSI_VGLS_DEFAULT | DSI_VGLS_SEL) -#define DSI_PWCTLR1_AP BIT(7) /* Gamma OP bias, max */ -#define DSI_PWCTLR1_APIS BIT(2) /* Source OP input bias, min */ -#define DSI_PWCTLR1_APOS BIT(0) /* Source OP output bias, min */ -#define DSI_CMD2_BK1_PWCTLR1_SET (DSI_PWCTLR1_AP | DSI_PWCTLR1_APIS | \ - DSI_PWCTLR1_APOS) -#define DSI_PWCTLR2_AVDD BIT(5) /* AVDD 6.6v */ -#define DSI_PWCTLR2_AVCL 0x0 /* AVCL -4.4v */ -#define DSI_CMD2_BK1_PWCTLR2_SET (DSI_PWCTLR2_AVDD | DSI_PWCTLR2_AVCL) -#define DSI_SPD1_T2D BIT(3) -#define DSI_CMD2_BK1_SPD1_SET (GENMASK(6, 4) | DSI_SPD1_T2D) -#define DSI_CMD2_BK1_SPD2_SET DSI_CMD2_BK1_SPD1_SET -#define DSI_MIPISET1_EOT_EN BIT(3) -#define DSI_CMD2_BK1_MIPISET1_SET (BIT(7) | DSI_MIPISET1_EOT_EN) +#define DSI_CMD2_BK1_VGLS_ONES BIT(6) +#define DSI_CMD2_BK1_VGLS_MASK GENMASK(3, 0) +#define DSI_CMD2_BK1_PWRCTRL1_AP_MASK GENMASK(7, 6) +#define DSI_CMD2_BK1_PWRCTRL1_APIS_MASK GENMASK(3, 2) +#define DSI_CMD2_BK1_PWRCTRL1_APOS_MASK GENMASK(1, 0) +#define DSI_CMD2_BK1_PWRCTRL2_AVDD_MASK GENMASK(5, 4) +#define DSI_CMD2_BK1_PWRCTRL2_AVCL_MASK GENMASK(1, 0) +#define DSI_CMD2_BK1_SPD1_ONES_MASK GENMASK(6, 4) +#define DSI_CMD2_BK1_SPD1_T2D_MASK GENMASK(3, 0) +#define DSI_CMD2_BK1_SPD2_ONES_MASK GENMASK(6, 4) +#define DSI_CMD2_BK1_SPD2_T3D_MASK GENMASK(3, 0) +#define DSI_CMD2_BK1_MIPISET1_ONES BIT(7) +#define DSI_CMD2_BK1_MIPISET1_EOT_EN BIT(3) + +#define CFIELD_PREP(_mask, _val) \ + (((typeof(_mask))(_val) << (__builtin_ffsll(_mask) - 1)) & (_mask)) + +enum op_bias { + OP_BIAS_OFF = 0, + OP_BIAS_MIN, + OP_BIAS_MIDDLE, + OP_BIAS_MAX +}; + +struct st7701; struct st7701_panel_desc { const struct drm_display_mode *mode; unsigned int lanes; - unsigned long flags; enum mipi_dsi_pixel_format format; - const char *const *supply_names; - unsigned int num_supplies; unsigned int panel_sleep_delay; + + /* TFT matrix driver configuration, panel specific. */ + const u8 pv_gamma[16]; /* Positive voltage gamma control */ + const u8 nv_gamma[16]; /* Negative voltage gamma control */ + const u8 nlinv; /* Inversion selection */ + const u32 vop_uv; /* Vop in uV */ + const u32 vcom_uv; /* Vcom in uV */ + const u16 vgh_mv; /* Vgh in mV */ + const s16 vgl_mv; /* Vgl in mV */ + const u16 avdd_mv; /* Avdd in mV */ + const s16 avcl_mv; /* Avcl in mV */ + const enum op_bias gamma_op_bias; + const enum op_bias input_op_bias; + const enum op_bias output_op_bias; + const u16 t2d_ns; /* T2D in ns */ + const u16 t3d_ns; /* T3D in ns */ + const bool eot_en; + + /* GIP sequence, fully custom and undocumented. */ + void (*gip_sequence)(struct st7701 *st7701); }; struct st7701 { @@ -101,7 +144,7 @@ struct st7701 { struct mipi_dsi_device *dsi; const struct st7701_panel_desc *desc; - struct regulator_bulk_data *supplies; + struct regulator_bulk_data supplies[2]; struct gpio_desc *reset; unsigned int sleep_delay; }; @@ -123,9 +166,37 @@ static inline int st7701_dsi_write(struct st7701 *st7701, const void *seq, st7701_dsi_write(st7701, d, ARRAY_SIZE(d)); \ } +static u8 st7701_vgls_map(struct st7701 *st7701) +{ + const struct st7701_panel_desc *desc = st7701->desc; + struct { + s32 vgl; + u8 val; + } map[16] = { + { -7060, 0x0 }, { -7470, 0x1 }, + { -7910, 0x2 }, { -8140, 0x3 }, + { -8650, 0x4 }, { -8920, 0x5 }, + { -9210, 0x6 }, { -9510, 0x7 }, + { -9830, 0x8 }, { -10170, 0x9 }, + { -10530, 0xa }, { -10910, 0xb }, + { -11310, 0xc }, { -11730, 0xd }, + { -12200, 0xe }, { -12690, 0xf } + }; + int i; + + for (i = 0; i < ARRAY_SIZE(map); i++) + if (desc->vgl_mv == map[i].vgl) + return map[i].val; + + return 0; +} + static void st7701_init_sequence(struct st7701 *st7701) { - const struct drm_display_mode *mode = st7701->desc->mode; + const struct st7701_panel_desc *desc = st7701->desc; + const struct drm_display_mode *mode = desc->mode; + const u8 linecount8 = mode->vdisplay / 8; + const u8 linecountrem2 = (mode->vdisplay % 8) / 2; ST7701_DSI(st7701, MIPI_DCS_SOFT_RESET, 0x00); @@ -139,34 +210,105 @@ static void st7701_init_sequence(struct st7701 *st7701) /* Command2, BK0 */ ST7701_DSI(st7701, DSI_CMD2BKX_SEL, 0x77, 0x01, 0x00, 0x00, DSI_CMD2BK0_SEL); - ST7701_DSI(st7701, DSI_CMD2_BK0_PVGAMCTRL, 0x00, 0x0E, 0x15, 0x0F, - 0x11, 0x08, 0x08, 0x08, 0x08, 0x23, 0x04, 0x13, 0x12, - 0x2B, 0x34, 0x1F); - ST7701_DSI(st7701, DSI_CMD2_BK0_NVGAMCTRL, 0x00, 0x0E, 0x95, 0x0F, - 0x13, 0x07, 0x09, 0x08, 0x08, 0x22, 0x04, 0x10, 0x0E, - 0x2C, 0x34, 0x1F); + mipi_dsi_dcs_write(st7701->dsi, DSI_CMD2_BK0_PVGAMCTRL, + desc->pv_gamma, ARRAY_SIZE(desc->pv_gamma)); + mipi_dsi_dcs_write(st7701->dsi, DSI_CMD2_BK0_NVGAMCTRL, + desc->nv_gamma, ARRAY_SIZE(desc->nv_gamma)); + /* + * Vertical line count configuration: + * Line[6:0]: select number of vertical lines of the TFT matrix in + * multiples of 8 lines + * LDE_EN: enable sub-8-line granularity line count + * Line_delta[1:0]: add 0/2/4/6 extra lines to line count selected + * using Line[6:0] + * + * Total number of vertical lines: + * LN = ((Line[6:0] + 1) * 8) + (LDE_EN ? Line_delta[1:0] * 2 : 0) + */ ST7701_DSI(st7701, DSI_CMD2_BK0_LNESET, - DSI_CMD2_BK0_LNESET_B0, DSI_CMD2_BK0_LNESET_B1); + FIELD_PREP(DSI_CMD2_BK0_LNESET_LINE_MASK, linecount8 - 1) | + (linecountrem2 ? DSI_CMD2_BK0_LNESET_LDE_EN : 0), + FIELD_PREP(DSI_CMD2_BK0_LNESET_LINEDELTA, linecountrem2)); ST7701_DSI(st7701, DSI_CMD2_BK0_PORCTRL, - DSI_CMD2_BK0_PORCTRL_B0(mode), - DSI_CMD2_BK0_PORCTRL_B1(mode)); + FIELD_PREP(DSI_CMD2_BK0_PORCTRL_VBP_MASK, + mode->vtotal - mode->vsync_end), + FIELD_PREP(DSI_CMD2_BK0_PORCTRL_VFP_MASK, + mode->vsync_start - mode->vdisplay)); + /* + * Horizontal pixel count configuration: + * PCLK = 512 + (RTNI[4:0] * 16) + * The PCLK is number of pixel clock per line, which matches + * mode htotal. The minimum is 512 PCLK. + */ ST7701_DSI(st7701, DSI_CMD2_BK0_INVSEL, - DSI_CMD2_BK0_INVSEL_B0, DSI_CMD2_BK0_INVSEL_B1); + DSI_CMD2_BK0_INVSEL_ONES_MASK | + FIELD_PREP(DSI_CMD2_BK0_INVSEL_NLINV_MASK, desc->nlinv), + FIELD_PREP(DSI_CMD2_BK0_INVSEL_RTNI_MASK, + DIV_ROUND_UP(mode->htotal, 16))); /* Command2, BK1 */ ST7701_DSI(st7701, DSI_CMD2BKX_SEL, 0x77, 0x01, 0x00, 0x00, DSI_CMD2BK1_SEL); - ST7701_DSI(st7701, DSI_CMD2_BK1_VRHS, DSI_CMD2_BK1_VRHA_SET); - ST7701_DSI(st7701, DSI_CMD2_BK1_VCOM, DSI_CMD2_BK1_VCOM_SET); - ST7701_DSI(st7701, DSI_CMD2_BK1_VGHSS, DSI_CMD2_BK1_VGHSS_SET); + + /* Vop = 3.5375V + (VRHA[7:0] * 0.0125V) */ + ST7701_DSI(st7701, DSI_CMD2_BK1_VRHS, + FIELD_PREP(DSI_CMD2_BK1_VRHA_MASK, + DIV_ROUND_CLOSEST(desc->vop_uv - 3537500, 12500))); + + /* Vcom = 0.1V + (VCOM[7:0] * 0.0125V) */ + ST7701_DSI(st7701, DSI_CMD2_BK1_VCOM, + FIELD_PREP(DSI_CMD2_BK1_VCOM_MASK, + DIV_ROUND_CLOSEST(desc->vcom_uv - 100000, 12500))); + + /* Vgh = 11.5V + (VGHSS[7:0] * 0.5V) */ + ST7701_DSI(st7701, DSI_CMD2_BK1_VGHSS, + FIELD_PREP(DSI_CMD2_BK1_VGHSS_MASK, + DIV_ROUND_CLOSEST(clamp(desc->vgh_mv, + (u16)11500, + (u16)17000) - 11500, + 500))); + ST7701_DSI(st7701, DSI_CMD2_BK1_TESTCMD, DSI_CMD2_BK1_TESTCMD_VAL); - ST7701_DSI(st7701, DSI_CMD2_BK1_VGLS, DSI_CMD2_BK1_VGLS_SET); - ST7701_DSI(st7701, DSI_CMD2_BK1_PWCTLR1, DSI_CMD2_BK1_PWCTLR1_SET); - ST7701_DSI(st7701, DSI_CMD2_BK1_PWCTLR2, DSI_CMD2_BK1_PWCTLR2_SET); - ST7701_DSI(st7701, DSI_CMD2_BK1_SPD1, DSI_CMD2_BK1_SPD1_SET); - ST7701_DSI(st7701, DSI_CMD2_BK1_SPD2, DSI_CMD2_BK1_SPD2_SET); - ST7701_DSI(st7701, DSI_CMD2_BK1_MIPISET1, DSI_CMD2_BK1_MIPISET1_SET); + /* Vgl is non-linear */ + ST7701_DSI(st7701, DSI_CMD2_BK1_VGLS, + DSI_CMD2_BK1_VGLS_ONES | + FIELD_PREP(DSI_CMD2_BK1_VGLS_MASK, st7701_vgls_map(st7701))); + + ST7701_DSI(st7701, DSI_CMD2_BK1_PWCTLR1, + FIELD_PREP(DSI_CMD2_BK1_PWRCTRL1_AP_MASK, + desc->gamma_op_bias) | + FIELD_PREP(DSI_CMD2_BK1_PWRCTRL1_APIS_MASK, + desc->input_op_bias) | + FIELD_PREP(DSI_CMD2_BK1_PWRCTRL1_APOS_MASK, + desc->output_op_bias)); + + /* Avdd = 6.2V + (AVDD[1:0] * 0.2V) , Avcl = -4.4V - (AVCL[1:0] * 0.2V) */ + ST7701_DSI(st7701, DSI_CMD2_BK1_PWCTLR2, + FIELD_PREP(DSI_CMD2_BK1_PWRCTRL2_AVDD_MASK, + DIV_ROUND_CLOSEST(desc->avdd_mv - 6200, 200)) | + FIELD_PREP(DSI_CMD2_BK1_PWRCTRL2_AVCL_MASK, + DIV_ROUND_CLOSEST(-4400 + desc->avcl_mv, 200))); + + /* T2D = 0.2us * T2D[3:0] */ + ST7701_DSI(st7701, DSI_CMD2_BK1_SPD1, + DSI_CMD2_BK1_SPD1_ONES_MASK | + FIELD_PREP(DSI_CMD2_BK1_SPD1_T2D_MASK, + DIV_ROUND_CLOSEST(desc->t2d_ns, 200))); + + /* T3D = 4us + (0.8us * T3D[3:0]) */ + ST7701_DSI(st7701, DSI_CMD2_BK1_SPD2, + DSI_CMD2_BK1_SPD2_ONES_MASK | + FIELD_PREP(DSI_CMD2_BK1_SPD2_T3D_MASK, + DIV_ROUND_CLOSEST(desc->t3d_ns - 4000, 800))); + + ST7701_DSI(st7701, DSI_CMD2_BK1_MIPISET1, + DSI_CMD2_BK1_MIPISET1_ONES | + (desc->eot_en ? DSI_CMD2_BK1_MIPISET1_EOT_EN : 0)); +} + +static void ts8550b_gip_sequence(struct st7701 *st7701) +{ /** * ST7701_SPEC_V1.2 is unable to provide enough information above this * specific command sequence, so grab the same from vendor BSP driver. @@ -188,10 +330,78 @@ static void st7701_init_sequence(struct st7701 *st7701) ST7701_DSI(st7701, 0xEC, 0x00, 0x00); ST7701_DSI(st7701, 0xED, 0xFF, 0xF1, 0x04, 0x56, 0x72, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0x27, 0x65, 0x40, 0x1F, 0xFF); +} + +static void dmt028vghmcmi_1a_gip_sequence(struct st7701 *st7701) +{ + ST7701_DSI(st7701, 0xEE, 0x42); + ST7701_DSI(st7701, 0xE0, 0x00, 0x00, 0x02); + + ST7701_DSI(st7701, 0xE1, + 0x04, 0xA0, 0x06, 0xA0, + 0x05, 0xA0, 0x07, 0xA0, + 0x00, 0x44, 0x44); + ST7701_DSI(st7701, 0xE2, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00); + ST7701_DSI(st7701, 0xE3, + 0x00, 0x00, 0x22, 0x22); + ST7701_DSI(st7701, 0xE4, 0x44, 0x44); + ST7701_DSI(st7701, 0xE5, + 0x0C, 0x90, 0xA0, 0xA0, + 0x0E, 0x92, 0xA0, 0xA0, + 0x08, 0x8C, 0xA0, 0xA0, + 0x0A, 0x8E, 0xA0, 0xA0); + ST7701_DSI(st7701, 0xE6, + 0x00, 0x00, 0x22, 0x22); + ST7701_DSI(st7701, 0xE7, 0x44, 0x44); + ST7701_DSI(st7701, 0xE8, + 0x0D, 0x91, 0xA0, 0xA0, + 0x0F, 0x93, 0xA0, 0xA0, + 0x09, 0x8D, 0xA0, 0xA0, + 0x0B, 0x8F, 0xA0, 0xA0); + ST7701_DSI(st7701, 0xEB, + 0x00, 0x00, 0xE4, 0xE4, + 0x44, 0x00, 0x00); + ST7701_DSI(st7701, 0xED, + 0xFF, 0xF5, 0x47, 0x6F, + 0x0B, 0xA1, 0xAB, 0xFF, + 0xFF, 0xBA, 0x1A, 0xB0, + 0xF6, 0x74, 0x5F, 0xFF); + ST7701_DSI(st7701, 0xEF, + 0x08, 0x08, 0x08, 0x40, + 0x3F, 0x64); + + ST7701_DSI(st7701, DSI_CMD2BKX_SEL, + 0x77, 0x01, 0x00, 0x00, DSI_CMD2BKX_SEL_NONE); + + ST7701_DSI(st7701, DSI_CMD2BKX_SEL, + 0x77, 0x01, 0x00, 0x00, DSI_CMD2BK3_SEL); + ST7701_DSI(st7701, 0xE6, 0x7C); + ST7701_DSI(st7701, 0xE8, 0x00, 0x0E); + + ST7701_DSI(st7701, DSI_CMD2BKX_SEL, + 0x77, 0x01, 0x00, 0x00, DSI_CMD2BKX_SEL_NONE); + ST7701_DSI(st7701, 0x11); + msleep(120); + + ST7701_DSI(st7701, DSI_CMD2BKX_SEL, + 0x77, 0x01, 0x00, 0x00, DSI_CMD2BK3_SEL); + ST7701_DSI(st7701, 0xE8, 0x00, 0x0C); + msleep(10); + ST7701_DSI(st7701, 0xE8, 0x00, 0x00); + + ST7701_DSI(st7701, DSI_CMD2BKX_SEL, + 0x77, 0x01, 0x00, 0x00, DSI_CMD2BKX_SEL_NONE); + ST7701_DSI(st7701, 0x11); + msleep(120); + ST7701_DSI(st7701, 0xE8, 0x00, 0x00); - /* disable Command2 */ ST7701_DSI(st7701, DSI_CMD2BKX_SEL, 0x77, 0x01, 0x00, 0x00, DSI_CMD2BKX_SEL_NONE); + + ST7701_DSI(st7701, 0x3A, 0x70); } static int st7701_prepare(struct drm_panel *panel) @@ -201,7 +411,7 @@ static int st7701_prepare(struct drm_panel *panel) gpiod_set_value(st7701->reset, 0); - ret = regulator_bulk_enable(st7701->desc->num_supplies, + ret = regulator_bulk_enable(ARRAY_SIZE(st7701->supplies), st7701->supplies); if (ret < 0) return ret; @@ -212,6 +422,13 @@ static int st7701_prepare(struct drm_panel *panel) st7701_init_sequence(st7701); + if (st7701->desc->gip_sequence) + st7701->desc->gip_sequence(st7701); + + /* Disable Command2 */ + ST7701_DSI(st7701, DSI_CMD2BKX_SEL, + 0x77, 0x01, 0x00, 0x00, DSI_CMD2BKX_SEL_NONE); + return 0; } @@ -254,7 +471,7 @@ static int st7701_unprepare(struct drm_panel *panel) */ msleep(st7701->sleep_delay); - regulator_bulk_disable(st7701->desc->num_supplies, st7701->supplies); + regulator_bulk_disable(ARRAY_SIZE(st7701->supplies), st7701->supplies); return 0; } @@ -310,46 +527,207 @@ static const struct drm_display_mode ts8550b_mode = { .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, }; -static const char * const ts8550b_supply_names[] = { - "VCC", - "IOVCC", -}; - static const struct st7701_panel_desc ts8550b_desc = { .mode = &ts8550b_mode, .lanes = 2, - .flags = MIPI_DSI_MODE_VIDEO, .format = MIPI_DSI_FMT_RGB888, - .supply_names = ts8550b_supply_names, - .num_supplies = ARRAY_SIZE(ts8550b_supply_names), .panel_sleep_delay = 80, /* panel need extra 80ms for sleep out cmd */ + + .pv_gamma = { + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC0_MASK, 0), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC4_MASK, 0xe), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC8_MASK, 0x15), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC16_MASK, 0xf), + + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC24_MASK, 0x11), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC52_MASK, 0x8), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC80_MASK, 0x8), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC108_MASK, 0x8), + + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC147_MASK, 0x8), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC175_MASK, 0x23), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC203_MASK, 0x4), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC231_MASK, 0x13), + + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC239_MASK, 0x12), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC247_MASK, 0x2b), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC251_MASK, 0x34), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1f) + }, + .nv_gamma = { + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC0_MASK, 0), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC4_MASK, 0xe), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0x2) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC8_MASK, 0x15), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC16_MASK, 0xf), + + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC24_MASK, 0x13), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC52_MASK, 0x7), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC80_MASK, 0x9), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC108_MASK, 0x8), + + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC147_MASK, 0x8), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC175_MASK, 0x22), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC203_MASK, 0x4), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC231_MASK, 0x10), + + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC239_MASK, 0xe), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC247_MASK, 0x2c), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC251_MASK, 0x34), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1f) + }, + .nlinv = 7, + .vop_uv = 4400000, + .vcom_uv = 337500, + .vgh_mv = 15000, + .vgl_mv = -9510, + .avdd_mv = 6600, + .avcl_mv = -4400, + .gamma_op_bias = OP_BIAS_MAX, + .input_op_bias = OP_BIAS_MIN, + .output_op_bias = OP_BIAS_MIN, + .t2d_ns = 1600, + .t3d_ns = 10400, + .eot_en = true, + .gip_sequence = ts8550b_gip_sequence, +}; + +static const struct drm_display_mode dmt028vghmcmi_1a_mode = { + .clock = 22325, + + .hdisplay = 480, + .hsync_start = 480 + 40, + .hsync_end = 480 + 40 + 4, + .htotal = 480 + 40 + 4 + 20, + + .vdisplay = 640, + .vsync_start = 640 + 2, + .vsync_end = 640 + 2 + 40, + .vtotal = 640 + 2 + 40 + 16, + + .width_mm = 56, + .height_mm = 78, + + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, +}; + +static const struct st7701_panel_desc dmt028vghmcmi_1a_desc = { + .mode = &dmt028vghmcmi_1a_mode, + .lanes = 2, + .format = MIPI_DSI_FMT_RGB888, + .panel_sleep_delay = 5, /* panel need extra 5ms for sleep out cmd */ + + .pv_gamma = { + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC0_MASK, 0), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC4_MASK, 0x10), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC8_MASK, 0x17), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC16_MASK, 0xd), + + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC24_MASK, 0x11), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC52_MASK, 0x6), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC80_MASK, 0x5), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC108_MASK, 0x8), + + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC147_MASK, 0x7), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC175_MASK, 0x1f), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC203_MASK, 0x4), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC231_MASK, 0x11), + + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC239_MASK, 0xe), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC247_MASK, 0x29), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC251_MASK, 0x30), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1f) + }, + .nv_gamma = { + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC0_MASK, 0), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC4_MASK, 0xd), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC8_MASK, 0x14), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC16_MASK, 0xe), + + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC24_MASK, 0x11), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC52_MASK, 0x6), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC80_MASK, 0x4), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC108_MASK, 0x8), + + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC147_MASK, 0x8), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC175_MASK, 0x20), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC203_MASK, 0x5), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC231_MASK, 0x13), + + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC239_MASK, 0x13), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC247_MASK, 0x26), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC251_MASK, 0x30), + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | + CFIELD_PREP(DSI_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1f) + }, + .nlinv = 1, + .vop_uv = 4800000, + .vcom_uv = 1650000, + .vgh_mv = 15000, + .vgl_mv = -10170, + .avdd_mv = 6600, + .avcl_mv = -4400, + .gamma_op_bias = OP_BIAS_MIDDLE, + .input_op_bias = OP_BIAS_MIN, + .output_op_bias = OP_BIAS_MIN, + .t2d_ns = 1600, + .t3d_ns = 10400, + .eot_en = true, + .gip_sequence = dmt028vghmcmi_1a_gip_sequence, }; static int st7701_dsi_probe(struct mipi_dsi_device *dsi) { const struct st7701_panel_desc *desc; struct st7701 *st7701; - int ret, i; + int ret; st7701 = devm_kzalloc(&dsi->dev, sizeof(*st7701), GFP_KERNEL); if (!st7701) return -ENOMEM; desc = of_device_get_match_data(&dsi->dev); - dsi->mode_flags = desc->flags; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS; dsi->format = desc->format; dsi->lanes = desc->lanes; - st7701->supplies = devm_kcalloc(&dsi->dev, desc->num_supplies, - sizeof(*st7701->supplies), - GFP_KERNEL); - if (!st7701->supplies) - return -ENOMEM; - - for (i = 0; i < desc->num_supplies; i++) - st7701->supplies[i].supply = desc->supply_names[i]; + st7701->supplies[0].supply = "VCC"; + st7701->supplies[1].supply = "IOVCC"; - ret = devm_regulator_bulk_get(&dsi->dev, desc->num_supplies, + ret = devm_regulator_bulk_get(&dsi->dev, ARRAY_SIZE(st7701->supplies), st7701->supplies); if (ret < 0) return ret; @@ -387,17 +765,16 @@ static int st7701_dsi_probe(struct mipi_dsi_device *dsi) return mipi_dsi_attach(dsi); } -static int st7701_dsi_remove(struct mipi_dsi_device *dsi) +static void st7701_dsi_remove(struct mipi_dsi_device *dsi) { struct st7701 *st7701 = mipi_dsi_get_drvdata(dsi); mipi_dsi_detach(dsi); drm_panel_remove(&st7701->panel); - - return 0; } static const struct of_device_id st7701_of_match[] = { + { .compatible = "densitron,dmt028vghmcmi-1a", .data = &dmt028vghmcmi_1a_desc }, { .compatible = "techstar,ts8550b", .data = &ts8550b_desc }, { } }; diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7703.c b/drivers/gpu/drm/panel/panel-sitronix-st7703.c index 73f69c929a75..86a472b01360 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7703.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7703.c @@ -598,7 +598,7 @@ static void st7703_shutdown(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); } -static int st7703_remove(struct mipi_dsi_device *dsi) +static void st7703_remove(struct mipi_dsi_device *dsi) { struct st7703 *ctx = mipi_dsi_get_drvdata(dsi); int ret; @@ -612,8 +612,6 @@ static int st7703_remove(struct mipi_dsi_device *dsi) drm_panel_remove(&ctx->panel); st7703_debugfs_remove(ctx); - - return 0; } static const struct of_device_id st7703_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-sony-tulip-truly-nt35521.c b/drivers/gpu/drm/panel/panel-sony-tulip-truly-nt35521.c index 69f07b15fca4..fa9be3c299c0 100644 --- a/drivers/gpu/drm/panel/panel-sony-tulip-truly-nt35521.c +++ b/drivers/gpu/drm/panel/panel-sony-tulip-truly-nt35521.c @@ -517,7 +517,7 @@ static int truly_nt35521_probe(struct mipi_dsi_device *dsi) return 0; } -static int truly_nt35521_remove(struct mipi_dsi_device *dsi) +static void truly_nt35521_remove(struct mipi_dsi_device *dsi) { struct truly_nt35521 *ctx = mipi_dsi_get_drvdata(dsi); int ret; @@ -527,8 +527,6 @@ static int truly_nt35521_remove(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); drm_panel_remove(&ctx->panel); - - return 0; } static const struct of_device_id truly_nt35521_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-tdo-tl070wsh30.c b/drivers/gpu/drm/panel/panel-tdo-tl070wsh30.c index 820731be7147..d8487bc6d611 100644 --- a/drivers/gpu/drm/panel/panel-tdo-tl070wsh30.c +++ b/drivers/gpu/drm/panel/panel-tdo-tl070wsh30.c @@ -210,7 +210,7 @@ static int tdo_tl070wsh30_panel_probe(struct mipi_dsi_device *dsi) return mipi_dsi_attach(dsi); } -static int tdo_tl070wsh30_panel_remove(struct mipi_dsi_device *dsi) +static void tdo_tl070wsh30_panel_remove(struct mipi_dsi_device *dsi) { struct tdo_tl070wsh30_panel *tdo_tl070wsh30 = mipi_dsi_get_drvdata(dsi); int err; @@ -222,8 +222,6 @@ static int tdo_tl070wsh30_panel_remove(struct mipi_dsi_device *dsi) drm_panel_remove(&tdo_tl070wsh30->base); drm_panel_disable(&tdo_tl070wsh30->base); drm_panel_unprepare(&tdo_tl070wsh30->base); - - return 0; } static void tdo_tl070wsh30_panel_shutdown(struct mipi_dsi_device *dsi) diff --git a/drivers/gpu/drm/panel/panel-truly-nt35597.c b/drivers/gpu/drm/panel/panel-truly-nt35597.c index 9ca5c7ff41d6..b31cffb660a7 100644 --- a/drivers/gpu/drm/panel/panel-truly-nt35597.c +++ b/drivers/gpu/drm/panel/panel-truly-nt35597.c @@ -616,7 +616,7 @@ err_panel_add: return ret; } -static int truly_nt35597_remove(struct mipi_dsi_device *dsi) +static void truly_nt35597_remove(struct mipi_dsi_device *dsi) { struct truly_nt35597 *ctx = mipi_dsi_get_drvdata(dsi); @@ -628,7 +628,6 @@ static int truly_nt35597_remove(struct mipi_dsi_device *dsi) } drm_panel_remove(&ctx->panel); - return 0; } static const struct of_device_id truly_nt35597_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-visionox-rm69299.c b/drivers/gpu/drm/panel/panel-visionox-rm69299.c index db2443ac81d3..ec228c269146 100644 --- a/drivers/gpu/drm/panel/panel-visionox-rm69299.c +++ b/drivers/gpu/drm/panel/panel-visionox-rm69299.c @@ -256,7 +256,7 @@ err_dsi_attach: return ret; } -static int visionox_rm69299_remove(struct mipi_dsi_device *dsi) +static void visionox_rm69299_remove(struct mipi_dsi_device *dsi) { struct visionox_rm69299 *ctx = mipi_dsi_get_drvdata(dsi); @@ -264,7 +264,6 @@ static int visionox_rm69299_remove(struct mipi_dsi_device *dsi) mipi_dsi_device_unregister(ctx->dsi); drm_panel_remove(&ctx->panel); - return 0; } static const struct of_device_id visionox_rm69299_of_match[] = { diff --git a/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c b/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c index 8177f5a360fb..2c54733ee241 100644 --- a/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c +++ b/drivers/gpu/drm/panel/panel-xinpeng-xpp055c272.c @@ -339,7 +339,7 @@ static void xpp055c272_shutdown(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); } -static int xpp055c272_remove(struct mipi_dsi_device *dsi) +static void xpp055c272_remove(struct mipi_dsi_device *dsi) { struct xpp055c272 *ctx = mipi_dsi_get_drvdata(dsi); int ret; @@ -351,8 +351,6 @@ static int xpp055c272_remove(struct mipi_dsi_device *dsi) dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); drm_panel_remove(&ctx->panel); - - return 0; } static const struct of_device_id xpp055c272_of_match[] = { diff --git a/drivers/gpu/drm/panfrost/Kconfig b/drivers/gpu/drm/panfrost/Kconfig index 86cdc0ce79e6..079600328be1 100644 --- a/drivers/gpu/drm/panfrost/Kconfig +++ b/drivers/gpu/drm/panfrost/Kconfig @@ -11,6 +11,7 @@ config DRM_PANFROST select DRM_GEM_SHMEM_HELPER select PM_DEVFREQ select DEVFREQ_GOV_SIMPLE_ONDEMAND + select WANT_DEV_COREDUMP help DRM driver for ARM Mali Midgard (T6xx, T7xx, T8xx) and Bifrost (G3x, G5x, G7x) GPUs. diff --git a/drivers/gpu/drm/panfrost/Makefile b/drivers/gpu/drm/panfrost/Makefile index b71935862417..7da2b3f02ed9 100644 --- a/drivers/gpu/drm/panfrost/Makefile +++ b/drivers/gpu/drm/panfrost/Makefile @@ -9,6 +9,7 @@ panfrost-y := \ panfrost_gpu.o \ panfrost_job.o \ panfrost_mmu.o \ - panfrost_perfcnt.o + panfrost_perfcnt.o \ + panfrost_dump.o obj-$(CONFIG_DRM_PANFROST) += panfrost.o diff --git a/drivers/gpu/drm/panfrost/panfrost_dump.c b/drivers/gpu/drm/panfrost/panfrost_dump.c new file mode 100644 index 000000000000..89056a1aac7d --- /dev/null +++ b/drivers/gpu/drm/panfrost/panfrost_dump.c @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright 2021 Collabora ltd. */ + +#include <linux/err.h> +#include <linux/device.h> +#include <linux/devcoredump.h> +#include <linux/moduleparam.h> +#include <linux/iosys-map.h> +#include <drm/panfrost_drm.h> +#include <drm/drm_device.h> + +#include "panfrost_job.h" +#include "panfrost_gem.h" +#include "panfrost_regs.h" +#include "panfrost_dump.h" +#include "panfrost_device.h" + +static bool panfrost_dump_core = true; +module_param_named(dump_core, panfrost_dump_core, bool, 0600); + +struct panfrost_dump_iterator { + void *start; + struct panfrost_dump_object_header *hdr; + void *data; +}; + +static const unsigned short panfrost_dump_registers[] = { + SHADER_READY_LO, + SHADER_READY_HI, + TILER_READY_LO, + TILER_READY_HI, + L2_READY_LO, + L2_READY_HI, + JOB_INT_MASK, + JOB_INT_STAT, + JS_HEAD_LO(0), + JS_HEAD_HI(0), + JS_TAIL_LO(0), + JS_TAIL_HI(0), + JS_AFFINITY_LO(0), + JS_AFFINITY_HI(0), + JS_CONFIG(0), + JS_STATUS(0), + JS_HEAD_NEXT_LO(0), + JS_HEAD_NEXT_HI(0), + JS_AFFINITY_NEXT_LO(0), + JS_AFFINITY_NEXT_HI(0), + JS_CONFIG_NEXT(0), + MMU_INT_MASK, + MMU_INT_STAT, + AS_TRANSTAB_LO(0), + AS_TRANSTAB_HI(0), + AS_MEMATTR_LO(0), + AS_MEMATTR_HI(0), + AS_FAULTSTATUS(0), + AS_FAULTADDRESS_LO(0), + AS_FAULTADDRESS_HI(0), + AS_STATUS(0), +}; + +static void panfrost_core_dump_header(struct panfrost_dump_iterator *iter, + u32 type, void *data_end) +{ + struct panfrost_dump_object_header *hdr = iter->hdr; + + hdr->magic = cpu_to_le32(PANFROSTDUMP_MAGIC); + hdr->type = cpu_to_le32(type); + hdr->file_offset = cpu_to_le32(iter->data - iter->start); + hdr->file_size = cpu_to_le32(data_end - iter->data); + + iter->hdr++; + iter->data += le32_to_cpu(hdr->file_size); +} + +static void +panfrost_core_dump_registers(struct panfrost_dump_iterator *iter, + struct panfrost_device *pfdev, + u32 as_nr, int slot) +{ + struct panfrost_dump_registers *dumpreg = iter->data; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(panfrost_dump_registers); i++, dumpreg++) { + unsigned int js_as_offset = 0; + unsigned int reg; + + if (panfrost_dump_registers[i] >= JS_BASE && + panfrost_dump_registers[i] <= JS_BASE + JS_SLOT_STRIDE) + js_as_offset = slot * JS_SLOT_STRIDE; + else if (panfrost_dump_registers[i] >= MMU_BASE && + panfrost_dump_registers[i] <= MMU_BASE + MMU_AS_STRIDE) + js_as_offset = (as_nr << MMU_AS_SHIFT); + + reg = panfrost_dump_registers[i] + js_as_offset; + + dumpreg->reg = cpu_to_le32(reg); + dumpreg->value = cpu_to_le32(gpu_read(pfdev, reg)); + } + + panfrost_core_dump_header(iter, PANFROSTDUMP_BUF_REG, dumpreg); +} + +void panfrost_core_dump(struct panfrost_job *job) +{ + struct panfrost_device *pfdev = job->pfdev; + struct panfrost_dump_iterator iter; + struct drm_gem_object *dbo; + unsigned int n_obj, n_bomap_pages; + __le64 *bomap, *bomap_start; + size_t file_size; + u32 as_nr; + int slot; + int ret, i; + + as_nr = job->mmu->as; + slot = panfrost_job_get_slot(job); + + /* Only catch the first event, or when manually re-armed */ + if (!panfrost_dump_core) + return; + panfrost_dump_core = false; + + /* At least, we dump registers and end marker */ + n_obj = 2; + n_bomap_pages = 0; + file_size = ARRAY_SIZE(panfrost_dump_registers) * + sizeof(struct panfrost_dump_registers); + + /* Add in the active buffer objects */ + for (i = 0; i < job->bo_count; i++) { + /* + * Even though the CPU could be configured to use 16K or 64K pages, this + * is a very unusual situation for most kernel setups on SoCs that have + * a Panfrost device. Also many places across the driver make the somewhat + * arbitrary assumption that Panfrost's MMU page size is the same as the CPU's, + * so let's have a sanity check to ensure that's always the case + */ + dbo = job->bos[i]; + WARN_ON(!IS_ALIGNED(dbo->size, PAGE_SIZE)); + + file_size += dbo->size; + n_bomap_pages += dbo->size >> PAGE_SHIFT; + n_obj++; + } + + /* If we have any buffer objects, add a bomap object */ + if (n_bomap_pages) { + file_size += n_bomap_pages * sizeof(*bomap); + n_obj++; + } + + /* Add the size of the headers */ + file_size += sizeof(*iter.hdr) * n_obj; + + /* + * Allocate the file in vmalloc memory, it's likely to be big. + * The reason behind these GFP flags is that we don't want to trigger the + * OOM killer in the event that not enough memory could be found for our + * dump file. We also don't want the allocator to do any error reporting, + * as the right behaviour is failing gracefully if a big enough buffer + * could not be allocated. + */ + iter.start = __vmalloc(file_size, GFP_KERNEL | __GFP_NOWARN | + __GFP_NORETRY); + if (!iter.start) { + dev_warn(pfdev->dev, "failed to allocate devcoredump file\n"); + return; + } + + /* Point the data member after the headers */ + iter.hdr = iter.start; + iter.data = &iter.hdr[n_obj]; + + memset(iter.hdr, 0, iter.data - iter.start); + + /* + * For now, we write the job identifier in the register dump header, + * so that we can decode the entire dump later with pandecode + */ + iter.hdr->reghdr.jc = cpu_to_le64(job->jc); + iter.hdr->reghdr.major = cpu_to_le32(PANFROSTDUMP_MAJOR); + iter.hdr->reghdr.minor = cpu_to_le32(PANFROSTDUMP_MINOR); + iter.hdr->reghdr.gpu_id = cpu_to_le32(pfdev->features.id); + iter.hdr->reghdr.nbos = cpu_to_le64(job->bo_count); + + panfrost_core_dump_registers(&iter, pfdev, as_nr, slot); + + /* Reserve space for the bomap */ + if (job->bo_count) { + bomap_start = bomap = iter.data; + memset(bomap, 0, sizeof(*bomap) * n_bomap_pages); + panfrost_core_dump_header(&iter, PANFROSTDUMP_BUF_BOMAP, + bomap + n_bomap_pages); + } + + for (i = 0; i < job->bo_count; i++) { + struct iosys_map map; + struct panfrost_gem_mapping *mapping; + struct panfrost_gem_object *bo; + struct sg_page_iter page_iter; + void *vaddr; + + bo = to_panfrost_bo(job->bos[i]); + mapping = job->mappings[i]; + + if (!bo->base.sgt) { + dev_err(pfdev->dev, "Panfrost Dump: BO has no sgt, cannot dump\n"); + iter.hdr->bomap.valid = 0; + goto dump_header; + } + + ret = drm_gem_shmem_vmap(&bo->base, &map); + if (ret) { + dev_err(pfdev->dev, "Panfrost Dump: couldn't map Buffer Object\n"); + iter.hdr->bomap.valid = 0; + goto dump_header; + } + + WARN_ON(!mapping->active); + + iter.hdr->bomap.data[0] = cpu_to_le32((bomap - bomap_start)); + + for_each_sgtable_page(bo->base.sgt, &page_iter, 0) { + struct page *page = sg_page_iter_page(&page_iter); + + if (!IS_ERR(page)) { + *bomap++ = cpu_to_le64(page_to_phys(page)); + } else { + dev_err(pfdev->dev, "Panfrost Dump: wrong page\n"); + *bomap++ = ~cpu_to_le64(0); + } + } + + iter.hdr->bomap.iova = cpu_to_le64(mapping->mmnode.start << PAGE_SHIFT); + + vaddr = map.vaddr; + memcpy(iter.data, vaddr, bo->base.base.size); + + drm_gem_shmem_vunmap(&bo->base, &map); + + iter.hdr->bomap.valid = cpu_to_le32(1); + +dump_header: panfrost_core_dump_header(&iter, PANFROSTDUMP_BUF_BO, iter.data + + bo->base.base.size); + } + panfrost_core_dump_header(&iter, PANFROSTDUMP_BUF_TRAILER, iter.data); + + dev_coredumpv(pfdev->dev, iter.start, iter.data - iter.start, GFP_KERNEL); +} diff --git a/drivers/gpu/drm/panfrost/panfrost_dump.h b/drivers/gpu/drm/panfrost/panfrost_dump.h new file mode 100644 index 000000000000..7d9bcefa5346 --- /dev/null +++ b/drivers/gpu/drm/panfrost/panfrost_dump.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2021 Collabora ltd. + */ + +#ifndef PANFROST_DUMP_H +#define PANFROST_DUMP_H + +struct panfrost_job; +void panfrost_core_dump(struct panfrost_job *job); + +#endif diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c index 7c4208476fbd..dbc597ab46fb 100644 --- a/drivers/gpu/drm/panfrost/panfrost_job.c +++ b/drivers/gpu/drm/panfrost/panfrost_job.c @@ -20,6 +20,7 @@ #include "panfrost_regs.h" #include "panfrost_gpu.h" #include "panfrost_mmu.h" +#include "panfrost_dump.h" #define JOB_TIMEOUT_MS 500 @@ -727,6 +728,8 @@ static enum drm_gpu_sched_stat panfrost_job_timedout(struct drm_sched_job job_read(pfdev, JS_TAIL_LO(js)), sched_job); + panfrost_core_dump(job); + atomic_set(&pfdev->reset.pending, 1); panfrost_reset(pfdev, sched_job); diff --git a/drivers/gpu/drm/panfrost/panfrost_regs.h b/drivers/gpu/drm/panfrost/panfrost_regs.h index accb4fa3adb8..919f44ac853d 100644 --- a/drivers/gpu/drm/panfrost/panfrost_regs.h +++ b/drivers/gpu/drm/panfrost/panfrost_regs.h @@ -226,23 +226,25 @@ #define JOB_INT_MASK_DONE(j) BIT(j) #define JS_BASE 0x1800 -#define JS_HEAD_LO(n) (JS_BASE + ((n) * 0x80) + 0x00) -#define JS_HEAD_HI(n) (JS_BASE + ((n) * 0x80) + 0x04) -#define JS_TAIL_LO(n) (JS_BASE + ((n) * 0x80) + 0x08) -#define JS_TAIL_HI(n) (JS_BASE + ((n) * 0x80) + 0x0c) -#define JS_AFFINITY_LO(n) (JS_BASE + ((n) * 0x80) + 0x10) -#define JS_AFFINITY_HI(n) (JS_BASE + ((n) * 0x80) + 0x14) -#define JS_CONFIG(n) (JS_BASE + ((n) * 0x80) + 0x18) -#define JS_XAFFINITY(n) (JS_BASE + ((n) * 0x80) + 0x1c) -#define JS_COMMAND(n) (JS_BASE + ((n) * 0x80) + 0x20) -#define JS_STATUS(n) (JS_BASE + ((n) * 0x80) + 0x24) -#define JS_HEAD_NEXT_LO(n) (JS_BASE + ((n) * 0x80) + 0x40) -#define JS_HEAD_NEXT_HI(n) (JS_BASE + ((n) * 0x80) + 0x44) -#define JS_AFFINITY_NEXT_LO(n) (JS_BASE + ((n) * 0x80) + 0x50) -#define JS_AFFINITY_NEXT_HI(n) (JS_BASE + ((n) * 0x80) + 0x54) -#define JS_CONFIG_NEXT(n) (JS_BASE + ((n) * 0x80) + 0x58) -#define JS_COMMAND_NEXT(n) (JS_BASE + ((n) * 0x80) + 0x60) -#define JS_FLUSH_ID_NEXT(n) (JS_BASE + ((n) * 0x80) + 0x70) +#define JS_SLOT_STRIDE 0x80 + +#define JS_HEAD_LO(n) (JS_BASE + ((n) * JS_SLOT_STRIDE) + 0x00) +#define JS_HEAD_HI(n) (JS_BASE + ((n) * JS_SLOT_STRIDE) + 0x04) +#define JS_TAIL_LO(n) (JS_BASE + ((n) * JS_SLOT_STRIDE) + 0x08) +#define JS_TAIL_HI(n) (JS_BASE + ((n) * JS_SLOT_STRIDE) + 0x0c) +#define JS_AFFINITY_LO(n) (JS_BASE + ((n) * JS_SLOT_STRIDE) + 0x10) +#define JS_AFFINITY_HI(n) (JS_BASE + ((n) * JS_SLOT_STRIDE) + 0x14) +#define JS_CONFIG(n) (JS_BASE + ((n) * JS_SLOT_STRIDE) + 0x18) +#define JS_XAFFINITY(n) (JS_BASE + ((n) * JS_SLOT_STRIDE) + 0x1c) +#define JS_COMMAND(n) (JS_BASE + ((n) * JS_SLOT_STRIDE) + 0x20) +#define JS_STATUS(n) (JS_BASE + ((n) * JS_SLOT_STRIDE) + 0x24) +#define JS_HEAD_NEXT_LO(n) (JS_BASE + ((n) * JS_SLOT_STRIDE) + 0x40) +#define JS_HEAD_NEXT_HI(n) (JS_BASE + ((n) * JS_SLOT_STRIDE) + 0x44) +#define JS_AFFINITY_NEXT_LO(n) (JS_BASE + ((n) * JS_SLOT_STRIDE) + 0x50) +#define JS_AFFINITY_NEXT_HI(n) (JS_BASE + ((n) * JS_SLOT_STRIDE) + 0x54) +#define JS_CONFIG_NEXT(n) (JS_BASE + ((n) * JS_SLOT_STRIDE) + 0x58) +#define JS_COMMAND_NEXT(n) (JS_BASE + ((n) * JS_SLOT_STRIDE) + 0x60) +#define JS_FLUSH_ID_NEXT(n) (JS_BASE + ((n) * JS_SLOT_STRIDE) + 0x70) /* Possible values of JS_CONFIG and JS_CONFIG_NEXT registers */ #define JS_CONFIG_START_FLUSH_CLEAN BIT(8) @@ -281,7 +283,9 @@ #define AS_COMMAND_FLUSH_MEM 0x05 /* Wait for memory accesses to complete, flush all the L1s cache then flush all L2 caches then issue a flush region command to all MMUs */ -#define MMU_AS(as) (0x2400 + ((as) << 6)) +#define MMU_BASE 0x2400 +#define MMU_AS_SHIFT 0x06 +#define MMU_AS(as) (MMU_BASE + ((as) << MMU_AS_SHIFT)) #define AS_TRANSTAB_LO(as) (MMU_AS(as) + 0x00) /* (RW) Translation Table Base Address for address space n, low word */ #define AS_TRANSTAB_HI(as) (MMU_AS(as) + 0x04) /* (RW) Translation Table Base Address for address space n, high word */ @@ -300,6 +304,8 @@ #define AS_FAULTEXTRA_LO(as) (MMU_AS(as) + 0x38) /* (RO) Secondary fault address for address space n, low word */ #define AS_FAULTEXTRA_HI(as) (MMU_AS(as) + 0x3C) /* (RO) Secondary fault address for address space n, high word */ +#define MMU_AS_STRIDE (1 << MMU_AS_SHIFT) + /* * Begin LPAE MMU TRANSTAB register values */ diff --git a/drivers/gpu/drm/pl111/Kconfig b/drivers/gpu/drm/pl111/Kconfig index 91ee05b01303..ad24cdf1d992 100644 --- a/drivers/gpu/drm/pl111/Kconfig +++ b/drivers/gpu/drm/pl111/Kconfig @@ -6,7 +6,7 @@ config DRM_PL111 depends on VEXPRESS_CONFIG || VEXPRESS_CONFIG=n depends on COMMON_CLK select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_BRIDGE select DRM_PANEL_BRIDGE select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE diff --git a/drivers/gpu/drm/pl111/pl111_display.c b/drivers/gpu/drm/pl111/pl111_display.c index 6263346f24c6..6afdf260a4e2 100644 --- a/drivers/gpu/drm/pl111/pl111_display.c +++ b/drivers/gpu/drm/pl111/pl111_display.c @@ -15,11 +15,11 @@ #include <linux/media-bus-format.h> #include <linux/of_graph.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_vblank.h> #include "pl111_drm.h" @@ -94,7 +94,7 @@ static int pl111_display_check(struct drm_simple_display_pipe *pipe, return -EINVAL; if (fb) { - u32 offset = drm_fb_cma_get_gem_addr(fb, pstate, 0); + u32 offset = drm_fb_dma_get_gem_addr(fb, pstate, 0); /* FB base address must be dword aligned. */ if (offset & 3) @@ -398,7 +398,7 @@ static void pl111_display_update(struct drm_simple_display_pipe *pipe, struct drm_framebuffer *fb = pstate->fb; if (fb) { - u32 addr = drm_fb_cma_get_gem_addr(fb, pstate, 0); + u32 addr = drm_fb_dma_get_gem_addr(fb, pstate, 0); writel(addr, priv->regs + CLCD_UBAS); } diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c index 19a4324bd356..eb25eedb5ee0 100644 --- a/drivers/gpu/drm/pl111/pl111_drv.c +++ b/drivers/gpu/drm/pl111/pl111_drv.c @@ -48,10 +48,9 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_of.h> #include <drm/drm_panel.h> @@ -208,10 +207,10 @@ pl111_gem_import_sg_table(struct drm_device *dev, if (priv->use_device_memory) return ERR_PTR(-EINVAL); - return drm_gem_cma_prime_import_sg_table(dev, attach, sgt); + return drm_gem_dma_prime_import_sg_table(dev, attach, sgt); } -DEFINE_DRM_GEM_CMA_FOPS(drm_fops); +DEFINE_DRM_GEM_DMA_FOPS(drm_fops); static const struct drm_driver pl111_drm_driver = { .driver_features = @@ -224,7 +223,7 @@ static const struct drm_driver pl111_drm_driver = { .major = 1, .minor = 0, .patchlevel = 0, - .dumb_create = drm_gem_cma_dumb_create, + .dumb_create = drm_gem_dma_dumb_create, .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_import_sg_table = pl111_gem_import_sg_table, diff --git a/drivers/gpu/drm/pl111/pl111_versatile.c b/drivers/gpu/drm/pl111/pl111_versatile.c index efb01a554574..1b436b75fd39 100644 --- a/drivers/gpu/drm/pl111/pl111_versatile.c +++ b/drivers/gpu/drm/pl111/pl111_versatile.c @@ -404,6 +404,7 @@ static int pl111_vexpress_clcd_init(struct device *dev, struct device_node *np, if (of_device_is_compatible(child, "arm,pl111")) { has_coretile_clcd = true; ct_clcd = child; + of_node_put(child); break; } if (of_device_is_compatible(child, "arm,hdlcd")) { diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 2e8949863d6b..a152a7c6db21 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -902,7 +902,7 @@ static const struct drm_plane_helper_funcs qxl_cursor_helper_funcs = { static const struct drm_plane_funcs qxl_cursor_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, - .destroy = drm_primary_helper_destroy, + .destroy = drm_plane_helper_destroy, .reset = drm_atomic_helper_plane_reset, .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, @@ -924,7 +924,7 @@ static const struct drm_plane_helper_funcs primary_helper_funcs = { static const struct drm_plane_funcs qxl_primary_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, - .destroy = drm_primary_helper_destroy, + .destroy = drm_plane_helper_destroy, .reset = drm_atomic_helper_plane_reset, .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c index b42a657e4c2f..695d9308d1f0 100644 --- a/drivers/gpu/drm/qxl/qxl_object.c +++ b/drivers/gpu/drm/qxl/qxl_object.c @@ -141,7 +141,7 @@ int qxl_bo_create(struct qxl_device *qdev, unsigned long size, qxl_ttm_placement_from_domain(bo, domain); bo->tbo.priority = priority; - r = ttm_bo_init_reserved(&qdev->mman.bdev, &bo->tbo, size, type, + r = ttm_bo_init_reserved(&qdev->mman.bdev, &bo->tbo, type, &bo->placement, 0, &ctx, NULL, NULL, &qxl_ttm_bo_destroy); if (unlikely(r != 0)) { diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index f12675e3d261..ca5598ae8bfc 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -38,7 +38,6 @@ #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_framebuffer_helper.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> #include <drm/radeon_drm.h> diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 6c4a6802ca96..00c33b24d5d3 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -202,9 +202,9 @@ int radeon_bo_create(struct radeon_device *rdev, radeon_ttm_placement_from_domain(bo, domain); /* Kernel allocation are uninterruptible */ down_read(&rdev->pm.mclk_lock); - r = ttm_bo_init(&rdev->mman.bdev, &bo->tbo, size, type, - &bo->placement, page_align, !kernel, sg, resv, - &radeon_ttm_bo_destroy); + r = ttm_bo_init_validate(&rdev->mman.bdev, &bo->tbo, type, + &bo->placement, page_align, !kernel, sg, resv, + &radeon_ttm_bo_destroy); up_read(&rdev->pm.mclk_lock); if (unlikely(r != 0)) { return r; diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig index f6e6a6d5d987..c959e8c6be7d 100644 --- a/drivers/gpu/drm/rcar-du/Kconfig +++ b/drivers/gpu/drm/rcar-du/Kconfig @@ -5,7 +5,7 @@ config DRM_RCAR_DU depends on ARM || ARM64 depends on ARCH_RENESAS || COMPILE_TEST select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select VIDEOMODE_HELPERS help Choose this option if you have an R-Car chipset. diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 621bbccb95d4..fd3b94649a01 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -17,9 +17,7 @@ #include <drm/drm_bridge.h> #include <drm/drm_crtc.h> #include <drm/drm_device.h> -#include <drm/drm_fb_cma_helper.h> -#include <drm/drm_gem_cma_helper.h> -#include <drm/drm_plane_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_vblank.h> #include "rcar_cmm.h" diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 70d85610d720..00ac233a115e 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -20,9 +20,8 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_managed.h> #include <drm/drm_probe_helper.h> @@ -579,7 +578,7 @@ const char *rcar_du_output_name(enum rcar_du_output output) * DRM operations */ -DEFINE_DRM_GEM_CMA_FOPS(rcar_du_fops); +DEFINE_DRM_GEM_DMA_FOPS(rcar_du_fops); static const struct drm_driver rcar_du_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index 761451ee5263..21881fb5e84a 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -11,9 +11,8 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_device.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_managed.h> #include <drm/drm_probe_helper.h> @@ -328,12 +327,12 @@ const struct rcar_du_format_info *rcar_du_format_info(u32 fourcc) */ static const struct drm_gem_object_funcs rcar_du_gem_funcs = { - .free = drm_gem_cma_object_free, - .print_info = drm_gem_cma_object_print_info, - .get_sg_table = drm_gem_cma_object_get_sg_table, - .vmap = drm_gem_cma_object_vmap, - .mmap = drm_gem_cma_object_mmap, - .vm_ops = &drm_gem_cma_vm_ops, + .free = drm_gem_dma_object_free, + .print_info = drm_gem_dma_object_print_info, + .get_sg_table = drm_gem_dma_object_get_sg_table, + .vmap = drm_gem_dma_object_vmap, + .mmap = drm_gem_dma_object_mmap, + .vm_ops = &drm_gem_dma_vm_ops, }; struct drm_gem_object *rcar_du_gem_prime_import_sg_table(struct drm_device *dev, @@ -341,33 +340,33 @@ struct drm_gem_object *rcar_du_gem_prime_import_sg_table(struct drm_device *dev, struct sg_table *sgt) { struct rcar_du_device *rcdu = to_rcar_du_device(dev); - struct drm_gem_cma_object *cma_obj; + struct drm_gem_dma_object *dma_obj; struct drm_gem_object *gem_obj; int ret; if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) - return drm_gem_cma_prime_import_sg_table(dev, attach, sgt); + return drm_gem_dma_prime_import_sg_table(dev, attach, sgt); - /* Create a CMA GEM buffer. */ - cma_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL); - if (!cma_obj) + /* Create a DMA GEM buffer. */ + dma_obj = kzalloc(sizeof(*dma_obj), GFP_KERNEL); + if (!dma_obj) return ERR_PTR(-ENOMEM); - gem_obj = &cma_obj->base; + gem_obj = &dma_obj->base; gem_obj->funcs = &rcar_du_gem_funcs; drm_gem_private_object_init(dev, gem_obj, attach->dmabuf->size); - cma_obj->map_noncoherent = false; + dma_obj->map_noncoherent = false; ret = drm_gem_create_mmap_offset(gem_obj); if (ret) { drm_gem_object_release(gem_obj); - kfree(cma_obj); + kfree(dma_obj); return ERR_PTR(ret); } - cma_obj->paddr = 0; - cma_obj->sgt = sgt; + dma_obj->dma_addr = 0; + dma_obj->sgt = sgt; return gem_obj; } @@ -390,7 +389,7 @@ int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev, args->pitch = roundup(min_pitch, align); - return drm_gem_cma_dumb_create_internal(file, dev, args); + return drm_gem_dma_dumb_create_internal(file, dev, args); } static struct drm_framebuffer * diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c index 501d79367e3e..9e1f0cbbf642 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c @@ -12,11 +12,10 @@ #include <drm/drm_blend.h> #include <drm/drm_crtc.h> #include <drm/drm_device.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_cma_helper.h> -#include <drm/drm_plane_helper.h> +#include <drm/drm_gem_dma_helper.h> #include "rcar_du_drv.h" #include "rcar_du_group.h" @@ -342,7 +341,7 @@ static void rcar_du_plane_setup_scanout(struct rcar_du_group *rgrp, if (state->source == RCAR_DU_PLANE_MEMORY) { struct drm_framebuffer *fb = state->state.fb; - struct drm_gem_cma_object *gem; + struct drm_gem_dma_object *gem; unsigned int i; if (state->format->planes == 2) @@ -351,8 +350,8 @@ static void rcar_du_plane_setup_scanout(struct rcar_du_group *rgrp, pitch = fb->pitches[0] * 8 / state->format->bpp; for (i = 0; i < state->format->planes; ++i) { - gem = drm_fb_cma_get_gem_obj(fb, i); - dma[i] = gem->paddr + fb->offsets[i]; + gem = drm_fb_dma_get_gem_obj(fb, i); + dma[i] = gem->dma_addr + fb->offsets[i]; } } else { pitch = drm_rect_width(&state->state.src) >> 16; @@ -607,8 +606,8 @@ int __rcar_du_plane_atomic_check(struct drm_plane *plane, return PTR_ERR(crtc_state); ret = drm_atomic_helper_check_plane_state(state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, true, true); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c index dbc68cdabcff..10b7f1d0877a 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c @@ -11,13 +11,12 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_blend.h> #include <drm/drm_crtc.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_managed.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_vblank.h> #include <linux/bitops.h> @@ -184,7 +183,7 @@ int rcar_du_vsp_map_fb(struct rcar_du_vsp *vsp, struct drm_framebuffer *fb, int ret; for (i = 0; i < fb->format->num_planes; ++i) { - struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(fb, i); + struct drm_gem_dma_object *gem = drm_fb_dma_get_gem_obj(fb, i); struct sg_table *sgt = &sg_tables[i]; if (gem->sgt) { @@ -213,7 +212,7 @@ int rcar_du_vsp_map_fb(struct rcar_du_vsp *vsp, struct drm_framebuffer *fb, } } else { ret = dma_get_sgtable(rcdu->dev, sgt, gem->vaddr, - gem->paddr, gem->base.size); + gem->dma_addr, gem->base.size); if (ret) goto fail; } diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 53c2d9980d48..1bf3e2829cd0 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -2,7 +2,7 @@ config DRM_ROCKCHIP tristate "DRM Support for Rockchip" depends on DRM && ROCKCHIP_IOMMU - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_KMS_HELPER select DRM_PANEL select VIDEOMODE_HELPERS diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 13ed33e74457..813f9f8c8698 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -18,7 +18,7 @@ #include <drm/drm_aperture.h> #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_of.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c index 985584147da1..614e97aaac80 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c @@ -10,7 +10,7 @@ #include <drm/drm.h> #include <drm/drm_gem.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_prime.h> #include <drm/drm_vma_manager.h> @@ -279,7 +279,7 @@ static const struct drm_gem_object_funcs rockchip_gem_object_funcs = { .vmap = rockchip_gem_prime_vmap, .vunmap = rockchip_gem_prime_vunmap, .mmap = rockchip_drm_gem_object_mmap, - .vm_ops = &drm_gem_cma_vm_ops, + .vm_ops = &drm_gem_dma_vm_ops, }; static struct rockchip_gem_object * diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index ad3958b6f8bf..bdd48f87d098 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -27,7 +27,6 @@ #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_framebuffer_helper.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_self_refresh_helper.h> #include <drm/drm_vblank.h> @@ -809,9 +808,9 @@ static int vop_plane_atomic_check(struct drm_plane *plane, const struct vop_win_data *win = vop_win->data; int ret; int min_scale = win->phy->scl ? FRAC_16_16(1, 8) : - DRM_PLANE_HELPER_NO_SCALING; + DRM_PLANE_NO_SCALING; int max_scale = win->phy->scl ? FRAC_16_16(8, 1) : - DRM_PLANE_HELPER_NO_SCALING; + DRM_PLANE_NO_SCALING; if (!crtc || WARN_ON(!fb)) return 0; @@ -1060,9 +1059,9 @@ static int vop_plane_atomic_async_check(struct drm_plane *plane, struct vop_win *vop_win = to_vop_win(plane); const struct vop_win_data *win = vop_win->data; int min_scale = win->phy->scl ? FRAC_16_16(1, 8) : - DRM_PLANE_HELPER_NO_SCALING; + DRM_PLANE_NO_SCALING; int max_scale = win->phy->scl ? FRAC_16_16(8, 1) : - DRM_PLANE_HELPER_NO_SCALING; + DRM_PLANE_NO_SCALING; struct drm_crtc_state *crtc_state; if (plane != new_plane_state->crtc->cursor) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index e4631f515ba4..552426d5d3a2 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -29,7 +29,6 @@ #include <drm/drm_debugfs.h> #include <drm/drm_flip_work.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 68317d3a7a27..e0ab14e0fb6b 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -592,7 +592,6 @@ int drm_sched_job_init(struct drm_sched_job *job, struct drm_sched_entity *entity, void *owner) { - drm_sched_entity_select_rq(entity); if (!entity->rq) return -ENOENT; @@ -628,7 +627,7 @@ void drm_sched_job_arm(struct drm_sched_job *job) struct drm_sched_entity *entity = job->entity; BUG_ON(!entity); - + drm_sched_entity_select_rq(entity); sched = entity->rq->sched; job->sched = sched; diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile deleted file mode 100644 index 5ba5f9138c95..000000000000 --- a/drivers/gpu/drm/selftests/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -test-drm_modeset-y := test-drm_modeset_common.o test-drm_plane_helper.o \ - test-drm_format.o test-drm_framebuffer.o \ - test-drm_damage_helper.o test-drm_dp_mst_helper.o \ - test-drm_rect.o - -obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o test-drm_cmdline_parser.o \ - test-drm_buddy.o diff --git a/drivers/gpu/drm/selftests/drm_buddy_selftests.h b/drivers/gpu/drm/selftests/drm_buddy_selftests.h deleted file mode 100644 index 455b756c4ae5..000000000000 --- a/drivers/gpu/drm/selftests/drm_buddy_selftests.h +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* List each unit test as selftest(name, function) - * - * The name is used as both an enum and expanded as igt__name to create - * a module parameter. It must be unique and legal for a C identifier. - * - * Tests are executed in order by igt/drm_buddy - */ -selftest(sanitycheck, igt_sanitycheck) /* keep first (selfcheck for igt) */ -selftest(buddy_alloc_limit, igt_buddy_alloc_limit) -selftest(buddy_alloc_range, igt_buddy_alloc_range) -selftest(buddy_alloc_optimistic, igt_buddy_alloc_optimistic) -selftest(buddy_alloc_pessimistic, igt_buddy_alloc_pessimistic) -selftest(buddy_alloc_smoke, igt_buddy_alloc_smoke) -selftest(buddy_alloc_pathological, igt_buddy_alloc_pathological) diff --git a/drivers/gpu/drm/selftests/drm_cmdline_selftests.h b/drivers/gpu/drm/selftests/drm_cmdline_selftests.h deleted file mode 100644 index 29e367db6118..000000000000 --- a/drivers/gpu/drm/selftests/drm_cmdline_selftests.h +++ /dev/null @@ -1,68 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* List each unit test as selftest(function) - * - * The name is used as both an enum and expanded as igt__name to create - * a module parameter. It must be unique and legal for a C identifier. - * - * Tests are executed in order by igt/drm_mm - */ - -#define cmdline_test(test) selftest(test, test) - -cmdline_test(drm_cmdline_test_force_d_only) -cmdline_test(drm_cmdline_test_force_D_only_dvi) -cmdline_test(drm_cmdline_test_force_D_only_hdmi) -cmdline_test(drm_cmdline_test_force_D_only_not_digital) -cmdline_test(drm_cmdline_test_force_e_only) -cmdline_test(drm_cmdline_test_margin_only) -cmdline_test(drm_cmdline_test_interlace_only) -cmdline_test(drm_cmdline_test_res) -cmdline_test(drm_cmdline_test_res_missing_x) -cmdline_test(drm_cmdline_test_res_missing_y) -cmdline_test(drm_cmdline_test_res_bad_y) -cmdline_test(drm_cmdline_test_res_missing_y_bpp) -cmdline_test(drm_cmdline_test_res_vesa) -cmdline_test(drm_cmdline_test_res_vesa_rblank) -cmdline_test(drm_cmdline_test_res_rblank) -cmdline_test(drm_cmdline_test_res_bpp) -cmdline_test(drm_cmdline_test_res_bad_bpp) -cmdline_test(drm_cmdline_test_res_refresh) -cmdline_test(drm_cmdline_test_res_bad_refresh) -cmdline_test(drm_cmdline_test_res_bpp_refresh) -cmdline_test(drm_cmdline_test_res_bpp_refresh_interlaced) -cmdline_test(drm_cmdline_test_res_bpp_refresh_margins) -cmdline_test(drm_cmdline_test_res_bpp_refresh_force_off) -cmdline_test(drm_cmdline_test_res_bpp_refresh_force_on_off) -cmdline_test(drm_cmdline_test_res_bpp_refresh_force_on) -cmdline_test(drm_cmdline_test_res_bpp_refresh_force_on_analog) -cmdline_test(drm_cmdline_test_res_bpp_refresh_force_on_digital) -cmdline_test(drm_cmdline_test_res_bpp_refresh_interlaced_margins_force_on) -cmdline_test(drm_cmdline_test_res_margins_force_on) -cmdline_test(drm_cmdline_test_res_vesa_margins) -cmdline_test(drm_cmdline_test_res_invalid_mode) -cmdline_test(drm_cmdline_test_res_bpp_wrong_place_mode) -cmdline_test(drm_cmdline_test_name) -cmdline_test(drm_cmdline_test_name_bpp) -cmdline_test(drm_cmdline_test_name_refresh) -cmdline_test(drm_cmdline_test_name_bpp_refresh) -cmdline_test(drm_cmdline_test_name_refresh_wrong_mode) -cmdline_test(drm_cmdline_test_name_refresh_invalid_mode) -cmdline_test(drm_cmdline_test_name_option) -cmdline_test(drm_cmdline_test_name_bpp_option) -cmdline_test(drm_cmdline_test_rotate_0) -cmdline_test(drm_cmdline_test_rotate_90) -cmdline_test(drm_cmdline_test_rotate_180) -cmdline_test(drm_cmdline_test_rotate_270) -cmdline_test(drm_cmdline_test_rotate_multiple) -cmdline_test(drm_cmdline_test_rotate_invalid_val) -cmdline_test(drm_cmdline_test_rotate_truncated) -cmdline_test(drm_cmdline_test_hmirror) -cmdline_test(drm_cmdline_test_vmirror) -cmdline_test(drm_cmdline_test_margin_options) -cmdline_test(drm_cmdline_test_multiple_options) -cmdline_test(drm_cmdline_test_invalid_option) -cmdline_test(drm_cmdline_test_bpp_extra_and_option) -cmdline_test(drm_cmdline_test_extra_and_option) -cmdline_test(drm_cmdline_test_freestanding_options) -cmdline_test(drm_cmdline_test_freestanding_force_e_and_options) -cmdline_test(drm_cmdline_test_panel_orientation) diff --git a/drivers/gpu/drm/selftests/drm_mm_selftests.h b/drivers/gpu/drm/selftests/drm_mm_selftests.h deleted file mode 100644 index 8c87c964176b..000000000000 --- a/drivers/gpu/drm/selftests/drm_mm_selftests.h +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* List each unit test as selftest(name, function) - * - * The name is used as both an enum and expanded as igt__name to create - * a module parameter. It must be unique and legal for a C identifier. - * - * Tests are executed in order by igt/drm_mm - */ -selftest(sanitycheck, igt_sanitycheck) /* keep first (selfcheck for igt) */ -selftest(init, igt_init) -selftest(debug, igt_debug) -selftest(reserve, igt_reserve) -selftest(insert, igt_insert) -selftest(replace, igt_replace) -selftest(insert_range, igt_insert_range) -selftest(align, igt_align) -selftest(frag, igt_frag) -selftest(align32, igt_align32) -selftest(align64, igt_align64) -selftest(evict, igt_evict) -selftest(evict_range, igt_evict_range) -selftest(bottomup, igt_bottomup) -selftest(lowest, igt_lowest) -selftest(topdown, igt_topdown) -selftest(highest, igt_highest) -selftest(color, igt_color) -selftest(color_evict, igt_color_evict) -selftest(color_evict_range, igt_color_evict_range) diff --git a/drivers/gpu/drm/selftests/drm_modeset_selftests.h b/drivers/gpu/drm/selftests/drm_modeset_selftests.h deleted file mode 100644 index 782e285ca383..000000000000 --- a/drivers/gpu/drm/selftests/drm_modeset_selftests.h +++ /dev/null @@ -1,40 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* List each unit test as selftest(name, function) - * - * The name is used as both an enum and expanded as igt__name to create - * a module parameter. It must be unique and legal for a C identifier. - * - * Tests are executed in order by igt/drm_selftests_helper - */ -selftest(drm_rect_clip_scaled_div_by_zero, igt_drm_rect_clip_scaled_div_by_zero) -selftest(drm_rect_clip_scaled_not_clipped, igt_drm_rect_clip_scaled_not_clipped) -selftest(drm_rect_clip_scaled_clipped, igt_drm_rect_clip_scaled_clipped) -selftest(drm_rect_clip_scaled_signed_vs_unsigned, igt_drm_rect_clip_scaled_signed_vs_unsigned) -selftest(check_plane_state, igt_check_plane_state) -selftest(check_drm_format_block_width, igt_check_drm_format_block_width) -selftest(check_drm_format_block_height, igt_check_drm_format_block_height) -selftest(check_drm_format_min_pitch, igt_check_drm_format_min_pitch) -selftest(check_drm_framebuffer_create, igt_check_drm_framebuffer_create) -selftest(damage_iter_no_damage, igt_damage_iter_no_damage) -selftest(damage_iter_no_damage_fractional_src, igt_damage_iter_no_damage_fractional_src) -selftest(damage_iter_no_damage_src_moved, igt_damage_iter_no_damage_src_moved) -selftest(damage_iter_no_damage_fractional_src_moved, igt_damage_iter_no_damage_fractional_src_moved) -selftest(damage_iter_no_damage_not_visible, igt_damage_iter_no_damage_not_visible) -selftest(damage_iter_no_damage_no_crtc, igt_damage_iter_no_damage_no_crtc) -selftest(damage_iter_no_damage_no_fb, igt_damage_iter_no_damage_no_fb) -selftest(damage_iter_simple_damage, igt_damage_iter_simple_damage) -selftest(damage_iter_single_damage, igt_damage_iter_single_damage) -selftest(damage_iter_single_damage_intersect_src, igt_damage_iter_single_damage_intersect_src) -selftest(damage_iter_single_damage_outside_src, igt_damage_iter_single_damage_outside_src) -selftest(damage_iter_single_damage_fractional_src, igt_damage_iter_single_damage_fractional_src) -selftest(damage_iter_single_damage_intersect_fractional_src, igt_damage_iter_single_damage_intersect_fractional_src) -selftest(damage_iter_single_damage_outside_fractional_src, igt_damage_iter_single_damage_outside_fractional_src) -selftest(damage_iter_single_damage_src_moved, igt_damage_iter_single_damage_src_moved) -selftest(damage_iter_single_damage_fractional_src_moved, igt_damage_iter_single_damage_fractional_src_moved) -selftest(damage_iter_damage, igt_damage_iter_damage) -selftest(damage_iter_damage_one_intersect, igt_damage_iter_damage_one_intersect) -selftest(damage_iter_damage_one_outside, igt_damage_iter_damage_one_outside) -selftest(damage_iter_damage_src_moved, igt_damage_iter_damage_src_moved) -selftest(damage_iter_damage_not_visible, igt_damage_iter_damage_not_visible) -selftest(dp_mst_calc_pbn_mode, igt_dp_mst_calc_pbn_mode) -selftest(dp_mst_sideband_msg_req_decode, igt_dp_mst_sideband_msg_req_decode) diff --git a/drivers/gpu/drm/selftests/drm_selftest.c b/drivers/gpu/drm/selftests/drm_selftest.c deleted file mode 100644 index e29ed9faef5b..000000000000 --- a/drivers/gpu/drm/selftests/drm_selftest.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright © 2016 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include <linux/compiler.h> - -#define selftest(name, func) __idx_##name, -enum { -#include TESTS -}; -#undef selftest - -#define selftest(n, f) [__idx_##n] = { .name = #n, .func = f }, -static struct drm_selftest { - bool enabled; - const char *name; - int (*func)(void *); -} selftests[] = { -#include TESTS -}; -#undef selftest - -/* Embed the line number into the parameter name so that we can order tests */ -#define param(n) __PASTE(igt__, __PASTE(__PASTE(__LINE__, __), n)) -#define selftest_0(n, func, id) \ -module_param_named(id, selftests[__idx_##n].enabled, bool, 0400); -#define selftest(n, func) selftest_0(n, func, param(n)) -#include TESTS -#undef selftest - -static void set_default_test_all(struct drm_selftest *st, unsigned long count) -{ - unsigned long i; - - for (i = 0; i < count; i++) - if (st[i].enabled) - return; - - for (i = 0; i < count; i++) - st[i].enabled = true; -} - -static int run_selftests(struct drm_selftest *st, - unsigned long count, - void *data) -{ - int err = 0; - - set_default_test_all(st, count); - - /* Tests are listed in natural order in drm_*_selftests.h */ - for (; count--; st++) { - if (!st->enabled) - continue; - - pr_debug("drm: Running %s\n", st->name); - err = st->func(data); - if (err) - break; - } - - if (WARN(err > 0 || err == -ENOTTY, - "%s returned %d, conflicting with selftest's magic values!\n", - st->name, err)) - err = -1; - - rcu_barrier(); - return err; -} - -static int __maybe_unused -__drm_subtests(const char *caller, - const struct drm_subtest *st, - int count, - void *data) -{ - int err; - - for (; count--; st++) { - pr_debug("Running %s/%s\n", caller, st->name); - err = st->func(data); - if (err) { - pr_err("%s: %s failed with error %d\n", - caller, st->name, err); - return err; - } - } - - return 0; -} diff --git a/drivers/gpu/drm/selftests/drm_selftest.h b/drivers/gpu/drm/selftests/drm_selftest.h deleted file mode 100644 index c784ec02ff53..000000000000 --- a/drivers/gpu/drm/selftests/drm_selftest.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright © 2016 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#ifndef __DRM_SELFTEST_H__ -#define __DRM_SELFTEST_H__ - -struct drm_subtest { - int (*func)(void *data); - const char *name; -}; - -static int __drm_subtests(const char *caller, - const struct drm_subtest *st, - int count, - void *data); -#define drm_subtests(T, data) \ - __drm_subtests(__func__, T, ARRAY_SIZE(T), data) - -#define SUBTEST(x) { x, #x } - -#endif /* __DRM_SELFTEST_H__ */ diff --git a/drivers/gpu/drm/selftests/test-drm_buddy.c b/drivers/gpu/drm/selftests/test-drm_buddy.c deleted file mode 100644 index aca0c491040f..000000000000 --- a/drivers/gpu/drm/selftests/test-drm_buddy.c +++ /dev/null @@ -1,994 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Copyright © 2019 Intel Corporation - */ - -#define pr_fmt(fmt) "drm_buddy: " fmt - -#include <linux/module.h> -#include <linux/prime_numbers.h> -#include <linux/sched/signal.h> - -#include <drm/drm_buddy.h> - -#include "../lib/drm_random.h" - -#define TESTS "drm_buddy_selftests.h" -#include "drm_selftest.h" - -#define IGT_TIMEOUT(name__) \ - unsigned long name__ = jiffies + MAX_SCHEDULE_TIMEOUT - -static unsigned int random_seed; - -static inline u64 get_size(int order, u64 chunk_size) -{ - return (1 << order) * chunk_size; -} - -__printf(2, 3) -static bool __igt_timeout(unsigned long timeout, const char *fmt, ...) -{ - va_list va; - - if (!signal_pending(current)) { - cond_resched(); - if (time_before(jiffies, timeout)) - return false; - } - - if (fmt) { - va_start(va, fmt); - vprintk(fmt, va); - va_end(va); - } - - return true; -} - -static inline const char *yesno(bool v) -{ - return v ? "yes" : "no"; -} - -static void __igt_dump_block(struct drm_buddy *mm, - struct drm_buddy_block *block, - bool buddy) -{ - pr_err("block info: header=%llx, state=%u, order=%d, offset=%llx size=%llx root=%s buddy=%s\n", - block->header, - drm_buddy_block_state(block), - drm_buddy_block_order(block), - drm_buddy_block_offset(block), - drm_buddy_block_size(mm, block), - yesno(!block->parent), - yesno(buddy)); -} - -static void igt_dump_block(struct drm_buddy *mm, - struct drm_buddy_block *block) -{ - struct drm_buddy_block *buddy; - - __igt_dump_block(mm, block, false); - - buddy = drm_get_buddy(block); - if (buddy) - __igt_dump_block(mm, buddy, true); -} - -static int igt_check_block(struct drm_buddy *mm, - struct drm_buddy_block *block) -{ - struct drm_buddy_block *buddy; - unsigned int block_state; - u64 block_size; - u64 offset; - int err = 0; - - block_state = drm_buddy_block_state(block); - - if (block_state != DRM_BUDDY_ALLOCATED && - block_state != DRM_BUDDY_FREE && - block_state != DRM_BUDDY_SPLIT) { - pr_err("block state mismatch\n"); - err = -EINVAL; - } - - block_size = drm_buddy_block_size(mm, block); - offset = drm_buddy_block_offset(block); - - if (block_size < mm->chunk_size) { - pr_err("block size smaller than min size\n"); - err = -EINVAL; - } - - if (!is_power_of_2(block_size)) { - pr_err("block size not power of two\n"); - err = -EINVAL; - } - - if (!IS_ALIGNED(block_size, mm->chunk_size)) { - pr_err("block size not aligned to min size\n"); - err = -EINVAL; - } - - if (!IS_ALIGNED(offset, mm->chunk_size)) { - pr_err("block offset not aligned to min size\n"); - err = -EINVAL; - } - - if (!IS_ALIGNED(offset, block_size)) { - pr_err("block offset not aligned to block size\n"); - err = -EINVAL; - } - - buddy = drm_get_buddy(block); - - if (!buddy && block->parent) { - pr_err("buddy has gone fishing\n"); - err = -EINVAL; - } - - if (buddy) { - if (drm_buddy_block_offset(buddy) != (offset ^ block_size)) { - pr_err("buddy has wrong offset\n"); - err = -EINVAL; - } - - if (drm_buddy_block_size(mm, buddy) != block_size) { - pr_err("buddy size mismatch\n"); - err = -EINVAL; - } - - if (drm_buddy_block_state(buddy) == block_state && - block_state == DRM_BUDDY_FREE) { - pr_err("block and its buddy are free\n"); - err = -EINVAL; - } - } - - return err; -} - -static int igt_check_blocks(struct drm_buddy *mm, - struct list_head *blocks, - u64 expected_size, - bool is_contiguous) -{ - struct drm_buddy_block *block; - struct drm_buddy_block *prev; - u64 total; - int err = 0; - - block = NULL; - prev = NULL; - total = 0; - - list_for_each_entry(block, blocks, link) { - err = igt_check_block(mm, block); - - if (!drm_buddy_block_is_allocated(block)) { - pr_err("block not allocated\n"), - err = -EINVAL; - } - - if (is_contiguous && prev) { - u64 prev_block_size; - u64 prev_offset; - u64 offset; - - prev_offset = drm_buddy_block_offset(prev); - prev_block_size = drm_buddy_block_size(mm, prev); - offset = drm_buddy_block_offset(block); - - if (offset != (prev_offset + prev_block_size)) { - pr_err("block offset mismatch\n"); - err = -EINVAL; - } - } - - if (err) - break; - - total += drm_buddy_block_size(mm, block); - prev = block; - } - - if (!err) { - if (total != expected_size) { - pr_err("size mismatch, expected=%llx, found=%llx\n", - expected_size, total); - err = -EINVAL; - } - return err; - } - - if (prev) { - pr_err("prev block, dump:\n"); - igt_dump_block(mm, prev); - } - - pr_err("bad block, dump:\n"); - igt_dump_block(mm, block); - - return err; -} - -static int igt_check_mm(struct drm_buddy *mm) -{ - struct drm_buddy_block *root; - struct drm_buddy_block *prev; - unsigned int i; - u64 total; - int err = 0; - - if (!mm->n_roots) { - pr_err("n_roots is zero\n"); - return -EINVAL; - } - - if (mm->n_roots != hweight64(mm->size)) { - pr_err("n_roots mismatch, n_roots=%u, expected=%lu\n", - mm->n_roots, hweight64(mm->size)); - return -EINVAL; - } - - root = NULL; - prev = NULL; - total = 0; - - for (i = 0; i < mm->n_roots; ++i) { - struct drm_buddy_block *block; - unsigned int order; - - root = mm->roots[i]; - if (!root) { - pr_err("root(%u) is NULL\n", i); - err = -EINVAL; - break; - } - - err = igt_check_block(mm, root); - - if (!drm_buddy_block_is_free(root)) { - pr_err("root not free\n"); - err = -EINVAL; - } - - order = drm_buddy_block_order(root); - - if (!i) { - if (order != mm->max_order) { - pr_err("max order root missing\n"); - err = -EINVAL; - } - } - - if (prev) { - u64 prev_block_size; - u64 prev_offset; - u64 offset; - - prev_offset = drm_buddy_block_offset(prev); - prev_block_size = drm_buddy_block_size(mm, prev); - offset = drm_buddy_block_offset(root); - - if (offset != (prev_offset + prev_block_size)) { - pr_err("root offset mismatch\n"); - err = -EINVAL; - } - } - - block = list_first_entry_or_null(&mm->free_list[order], - struct drm_buddy_block, - link); - if (block != root) { - pr_err("root mismatch at order=%u\n", order); - err = -EINVAL; - } - - if (err) - break; - - prev = root; - total += drm_buddy_block_size(mm, root); - } - - if (!err) { - if (total != mm->size) { - pr_err("expected mm size=%llx, found=%llx\n", mm->size, - total); - err = -EINVAL; - } - return err; - } - - if (prev) { - pr_err("prev root(%u), dump:\n", i - 1); - igt_dump_block(mm, prev); - } - - if (root) { - pr_err("bad root(%u), dump:\n", i); - igt_dump_block(mm, root); - } - - return err; -} - -static void igt_mm_config(u64 *size, u64 *chunk_size) -{ - DRM_RND_STATE(prng, random_seed); - u32 s, ms; - - /* Nothing fancy, just try to get an interesting bit pattern */ - - prandom_seed_state(&prng, random_seed); - - /* Let size be a random number of pages up to 8 GB (2M pages) */ - s = 1 + drm_prandom_u32_max_state((BIT(33 - 12)) - 1, &prng); - /* Let the chunk size be a random power of 2 less than size */ - ms = BIT(drm_prandom_u32_max_state(ilog2(s), &prng)); - /* Round size down to the chunk size */ - s &= -ms; - - /* Convert from pages to bytes */ - *chunk_size = (u64)ms << 12; - *size = (u64)s << 12; -} - -static int igt_buddy_alloc_pathological(void *arg) -{ - u64 mm_size, size, min_page_size, start = 0; - struct drm_buddy_block *block; - const int max_order = 3; - unsigned long flags = 0; - int order, top, err; - struct drm_buddy mm; - LIST_HEAD(blocks); - LIST_HEAD(holes); - LIST_HEAD(tmp); - - /* - * Create a pot-sized mm, then allocate one of each possible - * order within. This should leave the mm with exactly one - * page left. Free the largest block, then whittle down again. - * Eventually we will have a fully 50% fragmented mm. - */ - - mm_size = PAGE_SIZE << max_order; - err = drm_buddy_init(&mm, mm_size, PAGE_SIZE); - if (err) { - pr_err("buddy_init failed(%d)\n", err); - return err; - } - BUG_ON(mm.max_order != max_order); - - for (top = max_order; top; top--) { - /* Make room by freeing the largest allocated block */ - block = list_first_entry_or_null(&blocks, typeof(*block), link); - if (block) { - list_del(&block->link); - drm_buddy_free_block(&mm, block); - } - - for (order = top; order--; ) { - size = min_page_size = get_size(order, PAGE_SIZE); - err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, - min_page_size, &tmp, flags); - if (err) { - pr_info("buddy_alloc hit -ENOMEM with order=%d, top=%d\n", - order, top); - goto err; - } - - block = list_first_entry_or_null(&tmp, - struct drm_buddy_block, - link); - if (!block) { - pr_err("alloc_blocks has no blocks\n"); - err = -EINVAL; - goto err; - } - - list_move_tail(&block->link, &blocks); - } - - /* There should be one final page for this sub-allocation */ - size = min_page_size = get_size(0, PAGE_SIZE); - err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, min_page_size, &tmp, flags); - if (err) { - pr_info("buddy_alloc hit -ENOMEM for hole\n"); - goto err; - } - - block = list_first_entry_or_null(&tmp, - struct drm_buddy_block, - link); - if (!block) { - pr_err("alloc_blocks has no blocks\n"); - err = -EINVAL; - goto err; - } - - list_move_tail(&block->link, &holes); - - size = min_page_size = get_size(top, PAGE_SIZE); - err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, min_page_size, &tmp, flags); - if (!err) { - pr_info("buddy_alloc unexpectedly succeeded at top-order %d/%d, it should be full!", - top, max_order); - block = list_first_entry_or_null(&tmp, - struct drm_buddy_block, - link); - if (!block) { - pr_err("alloc_blocks has no blocks\n"); - err = -EINVAL; - goto err; - } - - list_move_tail(&block->link, &blocks); - err = -EINVAL; - goto err; - } - } - - drm_buddy_free_list(&mm, &holes); - - /* Nothing larger than blocks of chunk_size now available */ - for (order = 1; order <= max_order; order++) { - size = min_page_size = get_size(order, PAGE_SIZE); - err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, min_page_size, &tmp, flags); - if (!err) { - pr_info("buddy_alloc unexpectedly succeeded at order %d, it should be full!", - order); - block = list_first_entry_or_null(&tmp, - struct drm_buddy_block, - link); - if (!block) { - pr_err("alloc_blocks has no blocks\n"); - err = -EINVAL; - goto err; - } - - list_move_tail(&block->link, &blocks); - err = -EINVAL; - goto err; - } - } - - if (err) - err = 0; - -err: - list_splice_tail(&holes, &blocks); - drm_buddy_free_list(&mm, &blocks); - drm_buddy_fini(&mm); - return err; -} - -static int igt_buddy_alloc_smoke(void *arg) -{ - u64 mm_size, min_page_size, chunk_size, start = 0; - unsigned long flags = 0; - struct drm_buddy mm; - int *order; - int err, i; - - DRM_RND_STATE(prng, random_seed); - IGT_TIMEOUT(end_time); - - igt_mm_config(&mm_size, &chunk_size); - - err = drm_buddy_init(&mm, mm_size, chunk_size); - if (err) { - pr_err("buddy_init failed(%d)\n", err); - return err; - } - - order = drm_random_order(mm.max_order + 1, &prng); - if (!order) { - err = -ENOMEM; - goto out_fini; - } - - for (i = 0; i <= mm.max_order; ++i) { - struct drm_buddy_block *block; - int max_order = order[i]; - bool timeout = false; - LIST_HEAD(blocks); - u64 total, size; - LIST_HEAD(tmp); - int order; - - err = igt_check_mm(&mm); - if (err) { - pr_err("pre-mm check failed, abort\n"); - break; - } - - order = max_order; - total = 0; - - do { -retry: - size = min_page_size = get_size(order, chunk_size); - err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, - min_page_size, &tmp, flags); - if (err) { - if (err == -ENOMEM) { - pr_info("buddy_alloc hit -ENOMEM with order=%d\n", - order); - } else { - if (order--) { - err = 0; - goto retry; - } - - pr_err("buddy_alloc with order=%d failed(%d)\n", - order, err); - } - - break; - } - - block = list_first_entry_or_null(&tmp, - struct drm_buddy_block, - link); - if (!block) { - pr_err("alloc_blocks has no blocks\n"); - err = -EINVAL; - break; - } - - list_move_tail(&block->link, &blocks); - - if (drm_buddy_block_order(block) != order) { - pr_err("buddy_alloc order mismatch\n"); - err = -EINVAL; - break; - } - - total += drm_buddy_block_size(&mm, block); - - if (__igt_timeout(end_time, NULL)) { - timeout = true; - break; - } - } while (total < mm.size); - - if (!err) - err = igt_check_blocks(&mm, &blocks, total, false); - - drm_buddy_free_list(&mm, &blocks); - - if (!err) { - err = igt_check_mm(&mm); - if (err) - pr_err("post-mm check failed\n"); - } - - if (err || timeout) - break; - - cond_resched(); - } - - if (err == -ENOMEM) - err = 0; - - kfree(order); -out_fini: - drm_buddy_fini(&mm); - - return err; -} - -static int igt_buddy_alloc_pessimistic(void *arg) -{ - u64 mm_size, size, min_page_size, start = 0; - struct drm_buddy_block *block, *bn; - const unsigned int max_order = 16; - unsigned long flags = 0; - struct drm_buddy mm; - unsigned int order; - LIST_HEAD(blocks); - LIST_HEAD(tmp); - int err; - - /* - * Create a pot-sized mm, then allocate one of each possible - * order within. This should leave the mm with exactly one - * page left. - */ - - mm_size = PAGE_SIZE << max_order; - err = drm_buddy_init(&mm, mm_size, PAGE_SIZE); - if (err) { - pr_err("buddy_init failed(%d)\n", err); - return err; - } - BUG_ON(mm.max_order != max_order); - - for (order = 0; order < max_order; order++) { - size = min_page_size = get_size(order, PAGE_SIZE); - err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, min_page_size, &tmp, flags); - if (err) { - pr_info("buddy_alloc hit -ENOMEM with order=%d\n", - order); - goto err; - } - - block = list_first_entry_or_null(&tmp, - struct drm_buddy_block, - link); - if (!block) { - pr_err("alloc_blocks has no blocks\n"); - err = -EINVAL; - goto err; - } - - list_move_tail(&block->link, &blocks); - } - - /* And now the last remaining block available */ - size = min_page_size = get_size(0, PAGE_SIZE); - err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, min_page_size, &tmp, flags); - if (err) { - pr_info("buddy_alloc hit -ENOMEM on final alloc\n"); - goto err; - } - - block = list_first_entry_or_null(&tmp, - struct drm_buddy_block, - link); - if (!block) { - pr_err("alloc_blocks has no blocks\n"); - err = -EINVAL; - goto err; - } - - list_move_tail(&block->link, &blocks); - - /* Should be completely full! */ - for (order = max_order; order--; ) { - size = min_page_size = get_size(order, PAGE_SIZE); - err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, min_page_size, &tmp, flags); - if (!err) { - pr_info("buddy_alloc unexpectedly succeeded at order %d, it should be full!", - order); - block = list_first_entry_or_null(&tmp, - struct drm_buddy_block, - link); - if (!block) { - pr_err("alloc_blocks has no blocks\n"); - err = -EINVAL; - goto err; - } - - list_move_tail(&block->link, &blocks); - err = -EINVAL; - goto err; - } - } - - block = list_last_entry(&blocks, typeof(*block), link); - list_del(&block->link); - drm_buddy_free_block(&mm, block); - - /* As we free in increasing size, we make available larger blocks */ - order = 1; - list_for_each_entry_safe(block, bn, &blocks, link) { - list_del(&block->link); - drm_buddy_free_block(&mm, block); - - size = min_page_size = get_size(order, PAGE_SIZE); - err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, min_page_size, &tmp, flags); - if (err) { - pr_info("buddy_alloc (realloc) hit -ENOMEM with order=%d\n", - order); - goto err; - } - - block = list_first_entry_or_null(&tmp, - struct drm_buddy_block, - link); - if (!block) { - pr_err("alloc_blocks has no blocks\n"); - err = -EINVAL; - goto err; - } - - list_del(&block->link); - drm_buddy_free_block(&mm, block); - order++; - } - - /* To confirm, now the whole mm should be available */ - size = min_page_size = get_size(max_order, PAGE_SIZE); - err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, min_page_size, &tmp, flags); - if (err) { - pr_info("buddy_alloc (realloc) hit -ENOMEM with order=%d\n", - max_order); - goto err; - } - - block = list_first_entry_or_null(&tmp, - struct drm_buddy_block, - link); - if (!block) { - pr_err("alloc_blocks has no blocks\n"); - err = -EINVAL; - goto err; - } - - list_del(&block->link); - drm_buddy_free_block(&mm, block); - -err: - drm_buddy_free_list(&mm, &blocks); - drm_buddy_fini(&mm); - return err; -} - -static int igt_buddy_alloc_optimistic(void *arg) -{ - u64 mm_size, size, min_page_size, start = 0; - struct drm_buddy_block *block; - unsigned long flags = 0; - const int max_order = 16; - struct drm_buddy mm; - LIST_HEAD(blocks); - LIST_HEAD(tmp); - int order, err; - - /* - * Create a mm with one block of each order available, and - * try to allocate them all. - */ - - mm_size = PAGE_SIZE * ((1 << (max_order + 1)) - 1); - err = drm_buddy_init(&mm, - mm_size, - PAGE_SIZE); - if (err) { - pr_err("buddy_init failed(%d)\n", err); - return err; - } - - BUG_ON(mm.max_order != max_order); - - for (order = 0; order <= max_order; order++) { - size = min_page_size = get_size(order, PAGE_SIZE); - err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, min_page_size, &tmp, flags); - if (err) { - pr_info("buddy_alloc hit -ENOMEM with order=%d\n", - order); - goto err; - } - - block = list_first_entry_or_null(&tmp, - struct drm_buddy_block, - link); - if (!block) { - pr_err("alloc_blocks has no blocks\n"); - err = -EINVAL; - goto err; - } - - list_move_tail(&block->link, &blocks); - } - - /* Should be completely full! */ - size = min_page_size = get_size(0, PAGE_SIZE); - err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, min_page_size, &tmp, flags); - if (!err) { - pr_info("buddy_alloc unexpectedly succeeded, it should be full!"); - block = list_first_entry_or_null(&tmp, - struct drm_buddy_block, - link); - if (!block) { - pr_err("alloc_blocks has no blocks\n"); - err = -EINVAL; - goto err; - } - - list_move_tail(&block->link, &blocks); - err = -EINVAL; - goto err; - } else { - err = 0; - } - -err: - drm_buddy_free_list(&mm, &blocks); - drm_buddy_fini(&mm); - return err; -} - -static int igt_buddy_alloc_range(void *arg) -{ - unsigned long flags = DRM_BUDDY_RANGE_ALLOCATION; - u64 offset, size, rem, chunk_size, end; - unsigned long page_num; - struct drm_buddy mm; - LIST_HEAD(blocks); - int err; - - igt_mm_config(&size, &chunk_size); - - err = drm_buddy_init(&mm, size, chunk_size); - if (err) { - pr_err("buddy_init failed(%d)\n", err); - return err; - } - - err = igt_check_mm(&mm); - if (err) { - pr_err("pre-mm check failed, abort, abort, abort!\n"); - goto err_fini; - } - - rem = mm.size; - offset = 0; - - for_each_prime_number_from(page_num, 1, ULONG_MAX - 1) { - struct drm_buddy_block *block; - LIST_HEAD(tmp); - - size = min(page_num * mm.chunk_size, rem); - end = offset + size; - - err = drm_buddy_alloc_blocks(&mm, offset, end, size, mm.chunk_size, &tmp, flags); - if (err) { - if (err == -ENOMEM) { - pr_info("alloc_range hit -ENOMEM with size=%llx\n", - size); - } else { - pr_err("alloc_range with offset=%llx, size=%llx failed(%d)\n", - offset, size, err); - } - - break; - } - - block = list_first_entry_or_null(&tmp, - struct drm_buddy_block, - link); - if (!block) { - pr_err("alloc_range has no blocks\n"); - err = -EINVAL; - break; - } - - if (drm_buddy_block_offset(block) != offset) { - pr_err("alloc_range start offset mismatch, found=%llx, expected=%llx\n", - drm_buddy_block_offset(block), offset); - err = -EINVAL; - } - - if (!err) - err = igt_check_blocks(&mm, &tmp, size, true); - - list_splice_tail(&tmp, &blocks); - - if (err) - break; - - offset += size; - - rem -= size; - if (!rem) - break; - - cond_resched(); - } - - if (err == -ENOMEM) - err = 0; - - drm_buddy_free_list(&mm, &blocks); - - if (!err) { - err = igt_check_mm(&mm); - if (err) - pr_err("post-mm check failed\n"); - } - -err_fini: - drm_buddy_fini(&mm); - - return err; -} - -static int igt_buddy_alloc_limit(void *arg) -{ - u64 size = U64_MAX, start = 0; - struct drm_buddy_block *block; - unsigned long flags = 0; - LIST_HEAD(allocated); - struct drm_buddy mm; - int err; - - err = drm_buddy_init(&mm, size, PAGE_SIZE); - if (err) - return err; - - if (mm.max_order != DRM_BUDDY_MAX_ORDER) { - pr_err("mm.max_order(%d) != %d\n", - mm.max_order, DRM_BUDDY_MAX_ORDER); - err = -EINVAL; - goto out_fini; - } - - size = mm.chunk_size << mm.max_order; - err = drm_buddy_alloc_blocks(&mm, start, size, size, - PAGE_SIZE, &allocated, flags); - - if (unlikely(err)) - goto out_free; - - block = list_first_entry_or_null(&allocated, - struct drm_buddy_block, - link); - - if (!block) { - err = -EINVAL; - goto out_fini; - } - - if (drm_buddy_block_order(block) != mm.max_order) { - pr_err("block order(%d) != %d\n", - drm_buddy_block_order(block), mm.max_order); - err = -EINVAL; - goto out_free; - } - - if (drm_buddy_block_size(&mm, block) != - BIT_ULL(mm.max_order) * PAGE_SIZE) { - pr_err("block size(%llu) != %llu\n", - drm_buddy_block_size(&mm, block), - BIT_ULL(mm.max_order) * PAGE_SIZE); - err = -EINVAL; - goto out_free; - } - -out_free: - drm_buddy_free_list(&mm, &allocated); -out_fini: - drm_buddy_fini(&mm); - return err; -} - -static int igt_sanitycheck(void *ignored) -{ - pr_info("%s - ok!\n", __func__); - return 0; -} - -#include "drm_selftest.c" - -static int __init test_drm_buddy_init(void) -{ - int err; - - while (!random_seed) - random_seed = get_random_int(); - - pr_info("Testing DRM buddy manager (struct drm_buddy), with random_seed=0x%x\n", - random_seed); - err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL); - - return err > 0 ? 0 : err; -} - -static void __exit test_drm_buddy_exit(void) -{ -} - -module_init(test_drm_buddy_init); -module_exit(test_drm_buddy_exit); - -MODULE_AUTHOR("Intel Corporation"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c b/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c deleted file mode 100644 index d96cd890def6..000000000000 --- a/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c +++ /dev/null @@ -1,1141 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2019 Bootlin - */ - -#define pr_fmt(fmt) "drm_cmdline: " fmt - -#include <linux/kernel.h> -#include <linux/module.h> - -#include <drm/drm_connector.h> -#include <drm/drm_modes.h> - -#define TESTS "drm_cmdline_selftests.h" -#include "drm_selftest.h" -#include "test-drm_modeset_common.h" - -static const struct drm_connector no_connector = {}; - -static int drm_cmdline_test_force_e_only(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("e", - &no_connector, - &mode)); - FAIL_ON(mode.specified); - FAIL_ON(mode.refresh_specified); - FAIL_ON(mode.bpp_specified); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_ON); - - return 0; -} - -static int drm_cmdline_test_force_D_only_not_digital(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("D", - &no_connector, - &mode)); - FAIL_ON(mode.specified); - FAIL_ON(mode.refresh_specified); - FAIL_ON(mode.bpp_specified); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_ON); - - return 0; -} - -static const struct drm_connector connector_hdmi = { - .connector_type = DRM_MODE_CONNECTOR_HDMIB, -}; - -static int drm_cmdline_test_force_D_only_hdmi(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("D", - &connector_hdmi, - &mode)); - FAIL_ON(mode.specified); - FAIL_ON(mode.refresh_specified); - FAIL_ON(mode.bpp_specified); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_ON_DIGITAL); - - return 0; -} - -static const struct drm_connector connector_dvi = { - .connector_type = DRM_MODE_CONNECTOR_DVII, -}; - -static int drm_cmdline_test_force_D_only_dvi(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("D", - &connector_dvi, - &mode)); - FAIL_ON(mode.specified); - FAIL_ON(mode.refresh_specified); - FAIL_ON(mode.bpp_specified); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_ON_DIGITAL); - - return 0; -} - -static int drm_cmdline_test_force_d_only(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("d", - &no_connector, - &mode)); - FAIL_ON(mode.specified); - FAIL_ON(mode.refresh_specified); - FAIL_ON(mode.bpp_specified); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_OFF); - - return 0; -} - -static int drm_cmdline_test_margin_only(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(drm_mode_parse_command_line_for_connector("m", - &no_connector, - &mode)); - - return 0; -} - -static int drm_cmdline_test_interlace_only(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(drm_mode_parse_command_line_for_connector("i", - &no_connector, - &mode)); - - return 0; -} - -static int drm_cmdline_test_res(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - - FAIL_ON(mode.refresh_specified); - - FAIL_ON(mode.bpp_specified); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED); - - return 0; -} - -static int drm_cmdline_test_res_missing_x(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(drm_mode_parse_command_line_for_connector("x480", - &no_connector, - &mode)); - - return 0; -} - -static int drm_cmdline_test_res_missing_y(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(drm_mode_parse_command_line_for_connector("1024x", - &no_connector, - &mode)); - - return 0; -} - -static int drm_cmdline_test_res_bad_y(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(drm_mode_parse_command_line_for_connector("1024xtest", - &no_connector, - &mode)); - - return 0; -} - -static int drm_cmdline_test_res_missing_y_bpp(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(drm_mode_parse_command_line_for_connector("1024x-24", - &no_connector, - &mode)); - - return 0; -} - -static int drm_cmdline_test_res_vesa(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480M", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - - FAIL_ON(mode.refresh_specified); - - FAIL_ON(mode.bpp_specified); - - FAIL_ON(mode.rb); - FAIL_ON(!mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED); - - return 0; -} - -static int drm_cmdline_test_res_vesa_rblank(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480MR", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - - FAIL_ON(mode.refresh_specified); - - FAIL_ON(mode.bpp_specified); - - FAIL_ON(!mode.rb); - FAIL_ON(!mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED); - - return 0; -} - -static int drm_cmdline_test_res_rblank(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480R", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - - FAIL_ON(mode.refresh_specified); - - FAIL_ON(mode.bpp_specified); - - FAIL_ON(!mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED); - - return 0; -} - -static int drm_cmdline_test_res_bpp(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - - FAIL_ON(mode.refresh_specified); - - FAIL_ON(!mode.bpp_specified); - FAIL_ON(mode.bpp != 24); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED); - - return 0; -} - -static int drm_cmdline_test_res_bad_bpp(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(drm_mode_parse_command_line_for_connector("720x480-test", - &no_connector, - &mode)); - - return 0; -} - -static int drm_cmdline_test_res_refresh(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480@60", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - - FAIL_ON(!mode.refresh_specified); - FAIL_ON(mode.refresh != 60); - - FAIL_ON(mode.bpp_specified); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED); - - return 0; -} - -static int drm_cmdline_test_res_bad_refresh(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(drm_mode_parse_command_line_for_connector("720x480@refresh", - &no_connector, - &mode)); - - return 0; -} - -static int drm_cmdline_test_res_bpp_refresh(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - - FAIL_ON(!mode.refresh_specified); - FAIL_ON(mode.refresh != 60); - - FAIL_ON(!mode.bpp_specified); - FAIL_ON(mode.bpp != 24); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED); - - return 0; -} - -static int drm_cmdline_test_res_bpp_refresh_interlaced(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60i", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - - FAIL_ON(!mode.refresh_specified); - FAIL_ON(mode.refresh != 60); - - FAIL_ON(!mode.bpp_specified); - FAIL_ON(mode.bpp != 24); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(!mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED); - - return 0; -} - -static int drm_cmdline_test_res_bpp_refresh_margins(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60m", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - - FAIL_ON(!mode.refresh_specified); - FAIL_ON(mode.refresh != 60); - - FAIL_ON(!mode.bpp_specified); - FAIL_ON(mode.bpp != 24); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(!mode.margins); - FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED); - - return 0; -} - -static int drm_cmdline_test_res_bpp_refresh_force_off(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60d", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - - FAIL_ON(!mode.refresh_specified); - FAIL_ON(mode.refresh != 60); - - FAIL_ON(!mode.bpp_specified); - FAIL_ON(mode.bpp != 24); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_OFF); - - return 0; -} - -static int drm_cmdline_test_res_bpp_refresh_force_on_off(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(drm_mode_parse_command_line_for_connector("720x480-24@60de", - &no_connector, - &mode)); - - return 0; -} - -static int drm_cmdline_test_res_bpp_refresh_force_on(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60e", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - - FAIL_ON(!mode.refresh_specified); - FAIL_ON(mode.refresh != 60); - - FAIL_ON(!mode.bpp_specified); - FAIL_ON(mode.bpp != 24); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_ON); - - return 0; -} - -static int drm_cmdline_test_res_bpp_refresh_force_on_analog(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60D", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - - FAIL_ON(!mode.refresh_specified); - FAIL_ON(mode.refresh != 60); - - FAIL_ON(!mode.bpp_specified); - FAIL_ON(mode.bpp != 24); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_ON); - - return 0; -} - -static int drm_cmdline_test_res_bpp_refresh_force_on_digital(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - static const struct drm_connector connector = { - .connector_type = DRM_MODE_CONNECTOR_DVII, - }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60D", - &connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - - FAIL_ON(!mode.refresh_specified); - FAIL_ON(mode.refresh != 60); - - FAIL_ON(!mode.bpp_specified); - FAIL_ON(mode.bpp != 24); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_ON_DIGITAL); - - return 0; -} - -static int drm_cmdline_test_res_bpp_refresh_interlaced_margins_force_on(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60ime", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - - FAIL_ON(!mode.refresh_specified); - FAIL_ON(mode.refresh != 60); - - FAIL_ON(!mode.bpp_specified); - FAIL_ON(mode.bpp != 24); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(!mode.interlace); - FAIL_ON(!mode.margins); - FAIL_ON(mode.force != DRM_FORCE_ON); - - return 0; -} - -static int drm_cmdline_test_res_margins_force_on(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480me", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - - FAIL_ON(mode.refresh_specified); - - FAIL_ON(mode.bpp_specified); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(!mode.margins); - FAIL_ON(mode.force != DRM_FORCE_ON); - - return 0; -} - -static int drm_cmdline_test_res_vesa_margins(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480Mm", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - - FAIL_ON(mode.refresh_specified); - - FAIL_ON(mode.bpp_specified); - - FAIL_ON(mode.rb); - FAIL_ON(!mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(!mode.margins); - FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED); - - return 0; -} - -static int drm_cmdline_test_res_invalid_mode(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(drm_mode_parse_command_line_for_connector("720x480f", - &no_connector, - &mode)); - - return 0; -} - -static int drm_cmdline_test_res_bpp_wrong_place_mode(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(drm_mode_parse_command_line_for_connector("720x480e-24", - &no_connector, - &mode)); - - return 0; -} - -static int drm_cmdline_test_name(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC", - &no_connector, - &mode)); - FAIL_ON(strcmp(mode.name, "NTSC")); - FAIL_ON(mode.refresh_specified); - FAIL_ON(mode.bpp_specified); - - return 0; -} - -static int drm_cmdline_test_name_bpp(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC-24", - &no_connector, - &mode)); - FAIL_ON(strcmp(mode.name, "NTSC")); - - FAIL_ON(mode.refresh_specified); - - FAIL_ON(!mode.bpp_specified); - FAIL_ON(mode.bpp != 24); - - return 0; -} - -static int drm_cmdline_test_name_bpp_refresh(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC-24@60", - &no_connector, - &mode)); - - return 0; -} - -static int drm_cmdline_test_name_refresh(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC@60", - &no_connector, - &mode)); - - return 0; -} - -static int drm_cmdline_test_name_refresh_wrong_mode(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC@60m", - &no_connector, - &mode)); - - return 0; -} - -static int drm_cmdline_test_name_refresh_invalid_mode(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC@60f", - &no_connector, - &mode)); - - return 0; -} - -static int drm_cmdline_test_name_option(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC,rotate=180", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(strcmp(mode.name, "NTSC")); - FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180); - - return 0; -} - -static int drm_cmdline_test_name_bpp_option(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC-24,rotate=180", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(strcmp(mode.name, "NTSC")); - FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180); - FAIL_ON(!mode.bpp_specified); - FAIL_ON(mode.bpp != 24); - - return 0; -} - -static int drm_cmdline_test_rotate_0(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=0", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_0); - - FAIL_ON(mode.refresh_specified); - - FAIL_ON(mode.bpp_specified); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED); - - return 0; -} - -static int drm_cmdline_test_rotate_90(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=90", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_90); - - FAIL_ON(mode.refresh_specified); - - FAIL_ON(mode.bpp_specified); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED); - - return 0; -} - -static int drm_cmdline_test_rotate_180(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=180", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180); - - FAIL_ON(mode.refresh_specified); - - FAIL_ON(mode.bpp_specified); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED); - - return 0; -} - -static int drm_cmdline_test_rotate_270(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=270", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_270); - - FAIL_ON(mode.refresh_specified); - - FAIL_ON(mode.bpp_specified); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED); - - return 0; -} - -static int drm_cmdline_test_rotate_multiple(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,rotate=0,rotate=90", - &no_connector, - &mode)); - - return 0; -} - -static int drm_cmdline_test_rotate_invalid_val(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,rotate=42", - &no_connector, - &mode)); - - return 0; -} - -static int drm_cmdline_test_rotate_truncated(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,rotate=", - &no_connector, - &mode)); - - return 0; -} - -static int drm_cmdline_test_hmirror(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,reflect_x", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - FAIL_ON(mode.rotation_reflection != (DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_X)); - - FAIL_ON(mode.refresh_specified); - - FAIL_ON(mode.bpp_specified); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED); - - return 0; -} - -static int drm_cmdline_test_vmirror(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,reflect_y", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - FAIL_ON(mode.rotation_reflection != (DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_Y)); - - FAIL_ON(mode.refresh_specified); - - FAIL_ON(mode.bpp_specified); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED); - - return 0; -} - -static int drm_cmdline_test_margin_options(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,margin_right=14,margin_left=24,margin_bottom=36,margin_top=42", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - FAIL_ON(mode.tv_margins.right != 14); - FAIL_ON(mode.tv_margins.left != 24); - FAIL_ON(mode.tv_margins.bottom != 36); - FAIL_ON(mode.tv_margins.top != 42); - - FAIL_ON(mode.refresh_specified); - - FAIL_ON(mode.bpp_specified); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED); - - return 0; -} - -static int drm_cmdline_test_multiple_options(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=270,reflect_x", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - FAIL_ON(mode.rotation_reflection != (DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X)); - - FAIL_ON(mode.refresh_specified); - - FAIL_ON(mode.bpp_specified); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED); - - return 0; -} - -static int drm_cmdline_test_invalid_option(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,test=42", - &no_connector, - &mode)); - - return 0; -} - -static int drm_cmdline_test_bpp_extra_and_option(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24e,rotate=180", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180); - - FAIL_ON(mode.refresh_specified); - - FAIL_ON(!mode.bpp_specified); - FAIL_ON(mode.bpp != 24); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_ON); - - return 0; -} - -static int drm_cmdline_test_extra_and_option(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480e,rotate=180", - &no_connector, - &mode)); - FAIL_ON(!mode.specified); - FAIL_ON(mode.xres != 720); - FAIL_ON(mode.yres != 480); - FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180); - - FAIL_ON(mode.refresh_specified); - FAIL_ON(mode.bpp_specified); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_ON); - - return 0; -} - -static int drm_cmdline_test_freestanding_options(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("margin_right=14,margin_left=24,margin_bottom=36,margin_top=42", - &no_connector, - &mode)); - FAIL_ON(mode.specified); - FAIL_ON(mode.refresh_specified); - FAIL_ON(mode.bpp_specified); - - FAIL_ON(mode.tv_margins.right != 14); - FAIL_ON(mode.tv_margins.left != 24); - FAIL_ON(mode.tv_margins.bottom != 36); - FAIL_ON(mode.tv_margins.top != 42); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED); - - return 0; -} - -static int drm_cmdline_test_freestanding_force_e_and_options(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("e,margin_right=14,margin_left=24,margin_bottom=36,margin_top=42", - &no_connector, - &mode)); - FAIL_ON(mode.specified); - FAIL_ON(mode.refresh_specified); - FAIL_ON(mode.bpp_specified); - - FAIL_ON(mode.tv_margins.right != 14); - FAIL_ON(mode.tv_margins.left != 24); - FAIL_ON(mode.tv_margins.bottom != 36); - FAIL_ON(mode.tv_margins.top != 42); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_ON); - - return 0; -} - -static int drm_cmdline_test_panel_orientation(void *ignored) -{ - struct drm_cmdline_mode mode = { }; - - FAIL_ON(!drm_mode_parse_command_line_for_connector("panel_orientation=upside_down", - &no_connector, - &mode)); - FAIL_ON(mode.specified); - FAIL_ON(mode.refresh_specified); - FAIL_ON(mode.bpp_specified); - - FAIL_ON(mode.panel_orientation != DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP); - - FAIL_ON(mode.rb); - FAIL_ON(mode.cvt); - FAIL_ON(mode.interlace); - FAIL_ON(mode.margins); - FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED); - - return 0; -} - -#include "drm_selftest.c" - -static int __init test_drm_cmdline_init(void) -{ - int err; - - err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL); - - return err > 0 ? 0 : err; -} -module_init(test_drm_cmdline_init); - -MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/selftests/test-drm_damage_helper.c b/drivers/gpu/drm/selftests/test-drm_damage_helper.c deleted file mode 100644 index 816e1464a98f..000000000000 --- a/drivers/gpu/drm/selftests/test-drm_damage_helper.c +++ /dev/null @@ -1,668 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Test case for drm_damage_helper functions - */ - -#define pr_fmt(fmt) "drm_damage_helper: " fmt - -#include <drm/drm_damage_helper.h> -#include <drm/drm_framebuffer.h> -#include <drm/drm_plane.h> -#include <drm/drm_drv.h> - -#include "test-drm_modeset_common.h" - -struct drm_driver mock_driver; -static struct drm_device mock_device; -static struct drm_object_properties mock_obj_props; -static struct drm_plane mock_plane; -static struct drm_property mock_prop; - -static void mock_setup(struct drm_plane_state *state) -{ - static bool setup_done = false; - - state->plane = &mock_plane; - - if (setup_done) - return; - - /* just enough so that drm_plane_enable_fb_damage_clips() works */ - mock_device.driver = &mock_driver; - mock_device.mode_config.prop_fb_damage_clips = &mock_prop; - mock_plane.dev = &mock_device; - mock_obj_props.count = 0; - mock_plane.base.properties = &mock_obj_props; - mock_prop.base.id = 1; /* 0 is an invalid id */ - mock_prop.dev = &mock_device; - - drm_plane_enable_fb_damage_clips(&mock_plane); -} - -static void set_plane_src(struct drm_plane_state *state, int x1, int y1, int x2, - int y2) -{ - state->src.x1 = x1; - state->src.y1 = y1; - state->src.x2 = x2; - state->src.y2 = y2; -} - -static void set_damage_clip(struct drm_mode_rect *r, int x1, int y1, int x2, - int y2) -{ - r->x1 = x1; - r->y1 = y1; - r->x2 = x2; - r->y2 = y2; -} - -static void set_damage_blob(struct drm_property_blob *damage_blob, - struct drm_mode_rect *r, uint32_t size) -{ - damage_blob->length = size; - damage_blob->data = r; -} - -static void set_plane_damage(struct drm_plane_state *state, - struct drm_property_blob *damage_blob) -{ - state->fb_damage_clips = damage_blob; -} - -static bool check_damage_clip(struct drm_plane_state *state, struct drm_rect *r, - int x1, int y1, int x2, int y2) -{ - /* - * Round down x1/y1 and round up x2/y2. This is because damage is not in - * 16.16 fixed point so to catch all pixels. - */ - int src_x1 = state->src.x1 >> 16; - int src_y1 = state->src.y1 >> 16; - int src_x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF); - int src_y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF); - - if (x1 >= x2 || y1 >= y2) { - pr_err("Cannot have damage clip with no dimension.\n"); - return false; - } - - if (x1 < src_x1 || y1 < src_y1 || x2 > src_x2 || y2 > src_y2) { - pr_err("Damage cannot be outside rounded plane src.\n"); - return false; - } - - if (r->x1 != x1 || r->y1 != y1 || r->x2 != x2 || r->y2 != y2) { - pr_err("Damage = %d %d %d %d\n", r->x1, r->y1, r->x2, r->y2); - return false; - } - - return true; -} - -const struct drm_framebuffer fb = { - .width = 2048, - .height = 2048 -}; - -/* common mocked structs many tests need */ -#define MOCK_VARIABLES() \ - struct drm_plane_state old_state; \ - struct drm_plane_state state = { \ - .crtc = ZERO_SIZE_PTR, \ - .fb = (struct drm_framebuffer *) &fb, \ - .visible = true, \ - }; \ - mock_setup(&old_state); \ - mock_setup(&state); - -int igt_damage_iter_no_damage(void *ignored) -{ - struct drm_atomic_helper_damage_iter iter; - struct drm_rect clip; - uint32_t num_hits = 0; - - MOCK_VARIABLES(); - - /* Plane src same as fb size. */ - set_plane_src(&old_state, 0, 0, fb.width << 16, fb.height << 16); - set_plane_src(&state, 0, 0, fb.width << 16, fb.height << 16); - drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); - drm_atomic_for_each_plane_damage(&iter, &clip) - num_hits++; - - FAIL(num_hits != 1, "Should return plane src as damage."); - FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 2048, 2048)); - - return 0; -} - -int igt_damage_iter_no_damage_fractional_src(void *ignored) -{ - struct drm_atomic_helper_damage_iter iter; - struct drm_rect clip; - uint32_t num_hits = 0; - - MOCK_VARIABLES(); - - /* Plane src has fractional part. */ - set_plane_src(&old_state, 0x3fffe, 0x3fffe, - 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16)); - set_plane_src(&state, 0x3fffe, 0x3fffe, - 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16)); - drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); - drm_atomic_for_each_plane_damage(&iter, &clip) - num_hits++; - - FAIL(num_hits != 1, "Should return rounded off plane src as damage."); - FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772)); - - return 0; -} - -int igt_damage_iter_no_damage_src_moved(void *ignored) -{ - struct drm_atomic_helper_damage_iter iter; - struct drm_rect clip; - uint32_t num_hits = 0; - - MOCK_VARIABLES(); - - /* Plane src moved since old plane state. */ - set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16); - set_plane_src(&state, 10 << 16, 10 << 16, - (10 + 1024) << 16, (10 + 768) << 16); - drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); - drm_atomic_for_each_plane_damage(&iter, &clip) - num_hits++; - - FAIL(num_hits != 1, "Should return plane src as damage."); - FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778)); - - return 0; -} - -int igt_damage_iter_no_damage_fractional_src_moved(void *ignored) -{ - struct drm_atomic_helper_damage_iter iter; - struct drm_rect clip; - uint32_t num_hits = 0; - - MOCK_VARIABLES(); - - /* Plane src has fractional part and it moved since old plane state. */ - set_plane_src(&old_state, 0x3fffe, 0x3fffe, - 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16)); - set_plane_src(&state, 0x40002, 0x40002, - 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); - drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); - drm_atomic_for_each_plane_damage(&iter, &clip) - num_hits++; - - FAIL(num_hits != 1, "Should return plane src as damage."); - FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773)); - - return 0; -} - -int igt_damage_iter_no_damage_not_visible(void *ignored) -{ - struct drm_atomic_helper_damage_iter iter; - struct drm_rect clip; - uint32_t num_hits = 0; - - MOCK_VARIABLES(); - - state.visible = false; - - mock_setup(&old_state); - - set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16); - set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16); - drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); - drm_atomic_for_each_plane_damage(&iter, &clip) - num_hits++; - - FAIL(num_hits != 0, "Should have no damage."); - - return 0; -} - -int igt_damage_iter_no_damage_no_crtc(void *ignored) -{ - struct drm_atomic_helper_damage_iter iter; - struct drm_rect clip; - uint32_t num_hits = 0; - - MOCK_VARIABLES(); - - state.crtc = NULL; - - set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16); - set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16); - drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); - drm_atomic_for_each_plane_damage(&iter, &clip) - num_hits++; - - FAIL(num_hits != 0, "Should have no damage."); - - return 0; -} - -int igt_damage_iter_no_damage_no_fb(void *ignored) -{ - struct drm_atomic_helper_damage_iter iter; - struct drm_plane_state old_state; - struct drm_rect clip; - uint32_t num_hits = 0; - - struct drm_plane_state state = { - .crtc = ZERO_SIZE_PTR, - .fb = 0, - }; - - mock_setup(&old_state); - - set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16); - set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16); - drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); - drm_atomic_for_each_plane_damage(&iter, &clip) - num_hits++; - - FAIL(num_hits != 0, "Should have no damage."); - - return 0; -} - -int igt_damage_iter_simple_damage(void *ignored) -{ - struct drm_atomic_helper_damage_iter iter; - struct drm_property_blob damage_blob; - struct drm_mode_rect damage; - struct drm_rect clip; - uint32_t num_hits = 0; - - MOCK_VARIABLES(); - - set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16); - set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16); - /* Damage set to plane src */ - set_damage_clip(&damage, 0, 0, 1024, 768); - set_damage_blob(&damage_blob, &damage, sizeof(damage)); - set_plane_damage(&state, &damage_blob); - drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); - drm_atomic_for_each_plane_damage(&iter, &clip) - num_hits++; - - FAIL(num_hits != 1, "Should return damage when set."); - FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 1024, 768)); - - return 0; -} - -int igt_damage_iter_single_damage(void *ignored) -{ - struct drm_atomic_helper_damage_iter iter; - struct drm_property_blob damage_blob; - struct drm_mode_rect damage; - struct drm_rect clip; - uint32_t num_hits = 0; - - MOCK_VARIABLES(); - - set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16); - set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16); - set_damage_clip(&damage, 256, 192, 768, 576); - set_damage_blob(&damage_blob, &damage, sizeof(damage)); - set_plane_damage(&state, &damage_blob); - drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); - drm_atomic_for_each_plane_damage(&iter, &clip) - num_hits++; - - FAIL(num_hits != 1, "Should return damage when set."); - FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 768, 576)); - - return 0; -} - -int igt_damage_iter_single_damage_intersect_src(void *ignored) -{ - struct drm_atomic_helper_damage_iter iter; - struct drm_property_blob damage_blob; - struct drm_mode_rect damage; - struct drm_rect clip; - uint32_t num_hits = 0; - - MOCK_VARIABLES(); - - set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16); - set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16); - /* Damage intersect with plane src. */ - set_damage_clip(&damage, 256, 192, 1360, 768); - set_damage_blob(&damage_blob, &damage, sizeof(damage)); - set_plane_damage(&state, &damage_blob); - drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); - drm_atomic_for_each_plane_damage(&iter, &clip) - num_hits++; - - FAIL(num_hits != 1, "Should return damage clipped to src."); - FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 1024, 768)); - - return 0; -} - -int igt_damage_iter_single_damage_outside_src(void *ignored) -{ - struct drm_atomic_helper_damage_iter iter; - struct drm_property_blob damage_blob; - struct drm_mode_rect damage; - struct drm_rect clip; - uint32_t num_hits = 0; - - MOCK_VARIABLES(); - - set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16); - set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16); - /* Damage clip outside plane src */ - set_damage_clip(&damage, 1360, 1360, 1380, 1380); - set_damage_blob(&damage_blob, &damage, sizeof(damage)); - set_plane_damage(&state, &damage_blob); - drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); - drm_atomic_for_each_plane_damage(&iter, &clip) - num_hits++; - - FAIL(num_hits != 0, "Should have no damage."); - - return 0; -} - -int igt_damage_iter_single_damage_fractional_src(void *ignored) -{ - struct drm_atomic_helper_damage_iter iter; - struct drm_property_blob damage_blob; - struct drm_mode_rect damage; - struct drm_rect clip; - uint32_t num_hits = 0; - - MOCK_VARIABLES(); - - /* Plane src has fractional part. */ - set_plane_src(&old_state, 0x40002, 0x40002, - 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); - set_plane_src(&state, 0x40002, 0x40002, - 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); - set_damage_clip(&damage, 10, 10, 256, 330); - set_damage_blob(&damage_blob, &damage, sizeof(damage)); - set_plane_damage(&state, &damage_blob); - drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); - drm_atomic_for_each_plane_damage(&iter, &clip) - num_hits++; - - FAIL(num_hits != 1, "Should return damage when set."); - FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 256, 330)); - - return 0; -} - -int igt_damage_iter_single_damage_intersect_fractional_src(void *ignored) -{ - struct drm_atomic_helper_damage_iter iter; - struct drm_property_blob damage_blob; - struct drm_mode_rect damage; - struct drm_rect clip; - uint32_t num_hits = 0; - - MOCK_VARIABLES(); - - /* Plane src has fractional part. */ - set_plane_src(&old_state, 0x40002, 0x40002, - 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); - set_plane_src(&state, 0x40002, 0x40002, - 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); - /* Damage intersect with plane src. */ - set_damage_clip(&damage, 10, 1, 1360, 330); - set_damage_blob(&damage_blob, &damage, sizeof(damage)); - set_plane_damage(&state, &damage_blob); - drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); - drm_atomic_for_each_plane_damage(&iter, &clip) - num_hits++; - - FAIL(num_hits != 1, "Should return damage clipped to rounded off src."); - FAIL_ON(!check_damage_clip(&state, &clip, 10, 4, 1029, 330)); - - return 0; -} - -int igt_damage_iter_single_damage_outside_fractional_src(void *ignored) -{ - struct drm_atomic_helper_damage_iter iter; - struct drm_property_blob damage_blob; - struct drm_mode_rect damage; - struct drm_rect clip; - uint32_t num_hits = 0; - - MOCK_VARIABLES(); - - /* Plane src has fractional part. */ - set_plane_src(&old_state, 0x40002, 0x40002, - 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); - set_plane_src(&state, 0x40002, 0x40002, - 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); - /* Damage clip outside plane src */ - set_damage_clip(&damage, 1360, 1360, 1380, 1380); - set_damage_blob(&damage_blob, &damage, sizeof(damage)); - set_plane_damage(&state, &damage_blob); - drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); - drm_atomic_for_each_plane_damage(&iter, &clip) - num_hits++; - - FAIL(num_hits != 0, "Should have no damage."); - - return 0; -} - -int igt_damage_iter_single_damage_src_moved(void *ignored) -{ - struct drm_atomic_helper_damage_iter iter; - struct drm_property_blob damage_blob; - struct drm_mode_rect damage; - struct drm_rect clip; - uint32_t num_hits = 0; - - MOCK_VARIABLES(); - - /* Plane src moved since old plane state. */ - set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16); - set_plane_src(&state, 10 << 16, 10 << 16, - (10 + 1024) << 16, (10 + 768) << 16); - set_damage_clip(&damage, 20, 30, 256, 256); - set_damage_blob(&damage_blob, &damage, sizeof(damage)); - set_plane_damage(&state, &damage_blob); - drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); - drm_atomic_for_each_plane_damage(&iter, &clip) - num_hits++; - - FAIL(num_hits != 1, "Should return plane src as damage."); - FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778)); - - return 0; -} - -int igt_damage_iter_single_damage_fractional_src_moved(void *ignored) -{ - struct drm_atomic_helper_damage_iter iter; - struct drm_property_blob damage_blob; - struct drm_mode_rect damage; - struct drm_rect clip; - uint32_t num_hits = 0; - - MOCK_VARIABLES(); - - /* Plane src with fractional part moved since old plane state. */ - set_plane_src(&old_state, 0x3fffe, 0x3fffe, - 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16)); - set_plane_src(&state, 0x40002, 0x40002, - 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); - /* Damage intersect with plane src. */ - set_damage_clip(&damage, 20, 30, 1360, 256); - set_damage_blob(&damage_blob, &damage, sizeof(damage)); - set_plane_damage(&state, &damage_blob); - drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); - drm_atomic_for_each_plane_damage(&iter, &clip) - num_hits++; - - FAIL(num_hits != 1, "Should return rounded off plane src as damage."); - FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773)); - - return 0; -} - -int igt_damage_iter_damage(void *ignored) -{ - struct drm_atomic_helper_damage_iter iter; - struct drm_property_blob damage_blob; - struct drm_mode_rect damage[2]; - struct drm_rect clip; - uint32_t num_hits = 0; - - MOCK_VARIABLES(); - - set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16); - set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16); - /* 2 damage clips. */ - set_damage_clip(&damage[0], 20, 30, 200, 180); - set_damage_clip(&damage[1], 240, 200, 280, 250); - set_damage_blob(&damage_blob, &damage[0], sizeof(damage)); - set_plane_damage(&state, &damage_blob); - drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); - drm_atomic_for_each_plane_damage(&iter, &clip) { - if (num_hits == 0) - FAIL_ON(!check_damage_clip(&state, &clip, 20, 30, 200, 180)); - if (num_hits == 1) - FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250)); - num_hits++; - } - - FAIL(num_hits != 2, "Should return damage when set."); - - return 0; -} - -int igt_damage_iter_damage_one_intersect(void *ignored) -{ - struct drm_atomic_helper_damage_iter iter; - struct drm_property_blob damage_blob; - struct drm_mode_rect damage[2]; - struct drm_rect clip; - uint32_t num_hits = 0; - - MOCK_VARIABLES(); - - set_plane_src(&old_state, 0x40002, 0x40002, - 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); - set_plane_src(&state, 0x40002, 0x40002, - 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); - /* 2 damage clips, one intersect plane src. */ - set_damage_clip(&damage[0], 20, 30, 200, 180); - set_damage_clip(&damage[1], 2, 2, 1360, 1360); - set_damage_blob(&damage_blob, &damage[0], sizeof(damage)); - set_plane_damage(&state, &damage_blob); - drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); - drm_atomic_for_each_plane_damage(&iter, &clip) { - if (num_hits == 0) - FAIL_ON(!check_damage_clip(&state, &clip, 20, 30, 200, 180)); - if (num_hits == 1) - FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773)); - num_hits++; - } - - FAIL(num_hits != 2, "Should return damage when set."); - - return 0; -} - -int igt_damage_iter_damage_one_outside(void *ignored) -{ - struct drm_atomic_helper_damage_iter iter; - struct drm_property_blob damage_blob; - struct drm_mode_rect damage[2]; - struct drm_rect clip; - uint32_t num_hits = 0; - - MOCK_VARIABLES(); - - set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16); - set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16); - /* 2 damage clips, one outside plane src. */ - set_damage_clip(&damage[0], 1360, 1360, 1380, 1380); - set_damage_clip(&damage[1], 240, 200, 280, 250); - set_damage_blob(&damage_blob, &damage[0], sizeof(damage)); - set_plane_damage(&state, &damage_blob); - drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); - drm_atomic_for_each_plane_damage(&iter, &clip) - num_hits++; - - FAIL(num_hits != 1, "Should return damage when set."); - FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250)); - - return 0; -} - -int igt_damage_iter_damage_src_moved(void *ignored) -{ - struct drm_atomic_helper_damage_iter iter; - struct drm_property_blob damage_blob; - struct drm_mode_rect damage[2]; - struct drm_rect clip; - uint32_t num_hits = 0; - - MOCK_VARIABLES(); - - set_plane_src(&old_state, 0x40002, 0x40002, - 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); - set_plane_src(&state, 0x3fffe, 0x3fffe, - 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16)); - /* 2 damage clips, one outside plane src. */ - set_damage_clip(&damage[0], 1360, 1360, 1380, 1380); - set_damage_clip(&damage[1], 240, 200, 280, 250); - set_damage_blob(&damage_blob, &damage[0], sizeof(damage)); - set_plane_damage(&state, &damage_blob); - drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); - drm_atomic_for_each_plane_damage(&iter, &clip) - num_hits++; - - FAIL(num_hits != 1, "Should return round off plane src as damage."); - FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772)); - - return 0; -} - -int igt_damage_iter_damage_not_visible(void *ignored) -{ - struct drm_atomic_helper_damage_iter iter; - struct drm_property_blob damage_blob; - struct drm_mode_rect damage[2]; - struct drm_rect clip; - uint32_t num_hits = 0; - - MOCK_VARIABLES(); - - state.visible = false; - - set_plane_src(&old_state, 0x40002, 0x40002, - 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); - set_plane_src(&state, 0x3fffe, 0x3fffe, - 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16)); - /* 2 damage clips, one outside plane src. */ - set_damage_clip(&damage[0], 1360, 1360, 1380, 1380); - set_damage_clip(&damage[1], 240, 200, 280, 250); - set_damage_blob(&damage_blob, &damage[0], sizeof(damage)); - set_plane_damage(&state, &damage_blob); - drm_atomic_helper_damage_iter_init(&iter, &old_state, &state); - drm_atomic_for_each_plane_damage(&iter, &clip) - num_hits++; - - FAIL(num_hits != 0, "Should not return any damage."); - - return 0; -} diff --git a/drivers/gpu/drm/selftests/test-drm_format.c b/drivers/gpu/drm/selftests/test-drm_format.c deleted file mode 100644 index c5e212afa27a..000000000000 --- a/drivers/gpu/drm/selftests/test-drm_format.c +++ /dev/null @@ -1,280 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Test cases for the drm_format functions - */ - -#define pr_fmt(fmt) "drm_format: " fmt - -#include <linux/errno.h> -#include <linux/kernel.h> - -#include <drm/drm_fourcc.h> - -#include "test-drm_modeset_common.h" - -int igt_check_drm_format_block_width(void *ignored) -{ - const struct drm_format_info *info = NULL; - - /* Test invalid arguments */ - FAIL_ON(drm_format_info_block_width(info, 0) != 0); - FAIL_ON(drm_format_info_block_width(info, -1) != 0); - FAIL_ON(drm_format_info_block_width(info, 1) != 0); - - /* Test 1 plane format */ - info = drm_format_info(DRM_FORMAT_XRGB4444); - FAIL_ON(!info); - FAIL_ON(drm_format_info_block_width(info, 0) != 1); - FAIL_ON(drm_format_info_block_width(info, 1) != 0); - FAIL_ON(drm_format_info_block_width(info, -1) != 0); - - /* Test 2 planes format */ - info = drm_format_info(DRM_FORMAT_NV12); - FAIL_ON(!info); - FAIL_ON(drm_format_info_block_width(info, 0) != 1); - FAIL_ON(drm_format_info_block_width(info, 1) != 1); - FAIL_ON(drm_format_info_block_width(info, 2) != 0); - FAIL_ON(drm_format_info_block_width(info, -1) != 0); - - /* Test 3 planes format */ - info = drm_format_info(DRM_FORMAT_YUV422); - FAIL_ON(!info); - FAIL_ON(drm_format_info_block_width(info, 0) != 1); - FAIL_ON(drm_format_info_block_width(info, 1) != 1); - FAIL_ON(drm_format_info_block_width(info, 2) != 1); - FAIL_ON(drm_format_info_block_width(info, 3) != 0); - FAIL_ON(drm_format_info_block_width(info, -1) != 0); - - /* Test a tiled format */ - info = drm_format_info(DRM_FORMAT_X0L0); - FAIL_ON(!info); - FAIL_ON(drm_format_info_block_width(info, 0) != 2); - FAIL_ON(drm_format_info_block_width(info, 1) != 0); - FAIL_ON(drm_format_info_block_width(info, -1) != 0); - - return 0; -} - -int igt_check_drm_format_block_height(void *ignored) -{ - const struct drm_format_info *info = NULL; - - /* Test invalid arguments */ - FAIL_ON(drm_format_info_block_height(info, 0) != 0); - FAIL_ON(drm_format_info_block_height(info, -1) != 0); - FAIL_ON(drm_format_info_block_height(info, 1) != 0); - - /* Test 1 plane format */ - info = drm_format_info(DRM_FORMAT_XRGB4444); - FAIL_ON(!info); - FAIL_ON(drm_format_info_block_height(info, 0) != 1); - FAIL_ON(drm_format_info_block_height(info, 1) != 0); - FAIL_ON(drm_format_info_block_height(info, -1) != 0); - - /* Test 2 planes format */ - info = drm_format_info(DRM_FORMAT_NV12); - FAIL_ON(!info); - FAIL_ON(drm_format_info_block_height(info, 0) != 1); - FAIL_ON(drm_format_info_block_height(info, 1) != 1); - FAIL_ON(drm_format_info_block_height(info, 2) != 0); - FAIL_ON(drm_format_info_block_height(info, -1) != 0); - - /* Test 3 planes format */ - info = drm_format_info(DRM_FORMAT_YUV422); - FAIL_ON(!info); - FAIL_ON(drm_format_info_block_height(info, 0) != 1); - FAIL_ON(drm_format_info_block_height(info, 1) != 1); - FAIL_ON(drm_format_info_block_height(info, 2) != 1); - FAIL_ON(drm_format_info_block_height(info, 3) != 0); - FAIL_ON(drm_format_info_block_height(info, -1) != 0); - - /* Test a tiled format */ - info = drm_format_info(DRM_FORMAT_X0L0); - FAIL_ON(!info); - FAIL_ON(drm_format_info_block_height(info, 0) != 2); - FAIL_ON(drm_format_info_block_height(info, 1) != 0); - FAIL_ON(drm_format_info_block_height(info, -1) != 0); - - return 0; -} - -int igt_check_drm_format_min_pitch(void *ignored) -{ - const struct drm_format_info *info = NULL; - - /* Test invalid arguments */ - FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0); - FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0); - FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0); - - /* Test 1 plane 8 bits per pixel format */ - info = drm_format_info(DRM_FORMAT_RGB332); - FAIL_ON(!info); - FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0); - FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0); - FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0); - - FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 1); - FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 2); - FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 640); - FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 1024); - FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 1920); - FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 4096); - FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 671); - FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) != - (uint64_t)UINT_MAX); - FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)) != - (uint64_t)(UINT_MAX - 1)); - - /* Test 1 plane 16 bits per pixel format */ - info = drm_format_info(DRM_FORMAT_XRGB4444); - FAIL_ON(!info); - FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0); - FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0); - FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0); - - FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 2); - FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 4); - FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 1280); - FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 2048); - FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 3840); - FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 8192); - FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 1342); - FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) != - (uint64_t)UINT_MAX * 2); - FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)) != - (uint64_t)(UINT_MAX - 1) * 2); - - /* Test 1 plane 24 bits per pixel format */ - info = drm_format_info(DRM_FORMAT_RGB888); - FAIL_ON(!info); - FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0); - FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0); - FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0); - - FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 3); - FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 6); - FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 1920); - FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 3072); - FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 5760); - FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 12288); - FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 2013); - FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) != - (uint64_t)UINT_MAX * 3); - FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX - 1) != - (uint64_t)(UINT_MAX - 1) * 3); - - /* Test 1 plane 32 bits per pixel format */ - info = drm_format_info(DRM_FORMAT_ABGR8888); - FAIL_ON(!info); - FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0); - FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0); - FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0); - - FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 4); - FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 8); - FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 2560); - FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 4096); - FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 7680); - FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 16384); - FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 2684); - FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) != - (uint64_t)UINT_MAX * 4); - FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX - 1) != - (uint64_t)(UINT_MAX - 1) * 4); - - /* Test 2 planes format */ - info = drm_format_info(DRM_FORMAT_NV12); - FAIL_ON(!info); - FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0); - FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0); - FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0); - FAIL_ON(drm_format_info_min_pitch(info, 2, 0) != 0); - - FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 1); - FAIL_ON(drm_format_info_min_pitch(info, 1, 1) != 2); - FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 2); - FAIL_ON(drm_format_info_min_pitch(info, 1, 1) != 2); - FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 640); - FAIL_ON(drm_format_info_min_pitch(info, 1, 320) != 640); - FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 1024); - FAIL_ON(drm_format_info_min_pitch(info, 1, 512) != 1024); - FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 1920); - FAIL_ON(drm_format_info_min_pitch(info, 1, 960) != 1920); - FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 4096); - FAIL_ON(drm_format_info_min_pitch(info, 1, 2048) != 4096); - FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 671); - FAIL_ON(drm_format_info_min_pitch(info, 1, 336) != 672); - FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) != - (uint64_t)UINT_MAX); - FAIL_ON(drm_format_info_min_pitch(info, 1, UINT_MAX / 2 + 1) != - (uint64_t)UINT_MAX + 1); - FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)) != - (uint64_t)(UINT_MAX - 1)); - FAIL_ON(drm_format_info_min_pitch(info, 1, (UINT_MAX - 1) / 2) != - (uint64_t)(UINT_MAX - 1)); - - /* Test 3 planes 8 bits per pixel format */ - info = drm_format_info(DRM_FORMAT_YUV422); - FAIL_ON(!info); - FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0); - FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0); - FAIL_ON(drm_format_info_min_pitch(info, 2, 0) != 0); - FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0); - FAIL_ON(drm_format_info_min_pitch(info, 3, 0) != 0); - - FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 1); - FAIL_ON(drm_format_info_min_pitch(info, 1, 1) != 1); - FAIL_ON(drm_format_info_min_pitch(info, 2, 1) != 1); - FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 2); - FAIL_ON(drm_format_info_min_pitch(info, 1, 2) != 2); - FAIL_ON(drm_format_info_min_pitch(info, 2, 2) != 2); - FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 640); - FAIL_ON(drm_format_info_min_pitch(info, 1, 320) != 320); - FAIL_ON(drm_format_info_min_pitch(info, 2, 320) != 320); - FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 1024); - FAIL_ON(drm_format_info_min_pitch(info, 1, 512) != 512); - FAIL_ON(drm_format_info_min_pitch(info, 2, 512) != 512); - FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 1920); - FAIL_ON(drm_format_info_min_pitch(info, 1, 960) != 960); - FAIL_ON(drm_format_info_min_pitch(info, 2, 960) != 960); - FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 4096); - FAIL_ON(drm_format_info_min_pitch(info, 1, 2048) != 2048); - FAIL_ON(drm_format_info_min_pitch(info, 2, 2048) != 2048); - FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 671); - FAIL_ON(drm_format_info_min_pitch(info, 1, 336) != 336); - FAIL_ON(drm_format_info_min_pitch(info, 2, 336) != 336); - FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) != - (uint64_t)UINT_MAX); - FAIL_ON(drm_format_info_min_pitch(info, 1, UINT_MAX / 2 + 1) != - (uint64_t)UINT_MAX / 2 + 1); - FAIL_ON(drm_format_info_min_pitch(info, 2, UINT_MAX / 2 + 1) != - (uint64_t)UINT_MAX / 2 + 1); - FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1) / 2) != - (uint64_t)(UINT_MAX - 1) / 2); - FAIL_ON(drm_format_info_min_pitch(info, 1, (UINT_MAX - 1) / 2) != - (uint64_t)(UINT_MAX - 1) / 2); - FAIL_ON(drm_format_info_min_pitch(info, 2, (UINT_MAX - 1) / 2) != - (uint64_t)(UINT_MAX - 1) / 2); - - /* Test tiled format */ - info = drm_format_info(DRM_FORMAT_X0L2); - FAIL_ON(!info); - FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0); - FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0); - FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0); - - FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 2); - FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 4); - FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 1280); - FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 2048); - FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 3840); - FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 8192); - FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 1342); - FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) != - (uint64_t)UINT_MAX * 2); - FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX - 1) != - (uint64_t)(UINT_MAX - 1) * 2); - - return 0; -} diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.c b/drivers/gpu/drm/selftests/test-drm_modeset_common.c deleted file mode 100644 index 2a7f93774006..000000000000 --- a/drivers/gpu/drm/selftests/test-drm_modeset_common.c +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Common file for modeset selftests. - */ - -#include <linux/module.h> - -#include "test-drm_modeset_common.h" - -#define TESTS "drm_modeset_selftests.h" -#include "drm_selftest.h" - -#include "drm_selftest.c" - -static int __init test_drm_modeset_init(void) -{ - int err; - - err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL); - - return err > 0 ? 0 : err; -} - -static void __exit test_drm_modeset_exit(void) -{ -} - -module_init(test_drm_modeset_init); -module_exit(test_drm_modeset_exit); - -MODULE_AUTHOR("Intel Corporation"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.h b/drivers/gpu/drm/selftests/test-drm_modeset_common.h deleted file mode 100644 index cfb51d8da2bc..000000000000 --- a/drivers/gpu/drm/selftests/test-drm_modeset_common.h +++ /dev/null @@ -1,52 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - -#ifndef __TEST_DRM_MODESET_COMMON_H__ -#define __TEST_DRM_MODESET_COMMON_H__ - -#include <linux/errno.h> -#include <linux/printk.h> - -#define FAIL(test, msg, ...) \ - do { \ - if (test) { \ - pr_err("%s/%u: " msg, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ - return -EINVAL; \ - } \ - } while (0) - -#define FAIL_ON(x) FAIL((x), "%s", "FAIL_ON(" __stringify(x) ")\n") - -int igt_drm_rect_clip_scaled_div_by_zero(void *ignored); -int igt_drm_rect_clip_scaled_not_clipped(void *ignored); -int igt_drm_rect_clip_scaled_clipped(void *ignored); -int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored); -int igt_check_plane_state(void *ignored); -int igt_check_drm_format_block_width(void *ignored); -int igt_check_drm_format_block_height(void *ignored); -int igt_check_drm_format_min_pitch(void *ignored); -int igt_check_drm_framebuffer_create(void *ignored); -int igt_damage_iter_no_damage(void *ignored); -int igt_damage_iter_no_damage_fractional_src(void *ignored); -int igt_damage_iter_no_damage_src_moved(void *ignored); -int igt_damage_iter_no_damage_fractional_src_moved(void *ignored); -int igt_damage_iter_no_damage_not_visible(void *ignored); -int igt_damage_iter_no_damage_no_crtc(void *ignored); -int igt_damage_iter_no_damage_no_fb(void *ignored); -int igt_damage_iter_simple_damage(void *ignored); -int igt_damage_iter_single_damage(void *ignored); -int igt_damage_iter_single_damage_intersect_src(void *ignored); -int igt_damage_iter_single_damage_outside_src(void *ignored); -int igt_damage_iter_single_damage_fractional_src(void *ignored); -int igt_damage_iter_single_damage_intersect_fractional_src(void *ignored); -int igt_damage_iter_single_damage_outside_fractional_src(void *ignored); -int igt_damage_iter_single_damage_src_moved(void *ignored); -int igt_damage_iter_single_damage_fractional_src_moved(void *ignored); -int igt_damage_iter_damage(void *ignored); -int igt_damage_iter_damage_one_intersect(void *ignored); -int igt_damage_iter_damage_one_outside(void *ignored); -int igt_damage_iter_damage_src_moved(void *ignored); -int igt_damage_iter_damage_not_visible(void *ignored); -int igt_dp_mst_calc_pbn_mode(void *ignored); -int igt_dp_mst_sideband_msg_req_decode(void *ignored); - -#endif diff --git a/drivers/gpu/drm/selftests/test-drm_rect.c b/drivers/gpu/drm/selftests/test-drm_rect.c deleted file mode 100644 index 3a5ff38321f4..000000000000 --- a/drivers/gpu/drm/selftests/test-drm_rect.c +++ /dev/null @@ -1,223 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Test cases for the drm_rect functions - */ - -#define pr_fmt(fmt) "drm_rect: " fmt - -#include <linux/limits.h> - -#include <drm/drm_rect.h> - -#include "test-drm_modeset_common.h" - -int igt_drm_rect_clip_scaled_div_by_zero(void *ignored) -{ - struct drm_rect src, dst, clip; - bool visible; - - /* - * Make sure we don't divide by zero when dst - * width/height is zero and dst and clip do not intersect. - */ - drm_rect_init(&src, 0, 0, 0, 0); - drm_rect_init(&dst, 0, 0, 0, 0); - drm_rect_init(&clip, 1, 1, 1, 1); - visible = drm_rect_clip_scaled(&src, &dst, &clip); - FAIL(visible, "Destination not be visible\n"); - FAIL(drm_rect_visible(&src), "Source should not be visible\n"); - - drm_rect_init(&src, 0, 0, 0, 0); - drm_rect_init(&dst, 3, 3, 0, 0); - drm_rect_init(&clip, 1, 1, 1, 1); - visible = drm_rect_clip_scaled(&src, &dst, &clip); - FAIL(visible, "Destination not be visible\n"); - FAIL(drm_rect_visible(&src), "Source should not be visible\n"); - - return 0; -} - -int igt_drm_rect_clip_scaled_not_clipped(void *ignored) -{ - struct drm_rect src, dst, clip; - bool visible; - - /* 1:1 scaling */ - drm_rect_init(&src, 0, 0, 1 << 16, 1 << 16); - drm_rect_init(&dst, 0, 0, 1, 1); - drm_rect_init(&clip, 0, 0, 1, 1); - - visible = drm_rect_clip_scaled(&src, &dst, &clip); - - FAIL(src.x1 != 0 || src.x2 != 1 << 16 || - src.y1 != 0 || src.y2 != 1 << 16, - "Source badly clipped\n"); - FAIL(dst.x1 != 0 || dst.x2 != 1 || - dst.y1 != 0 || dst.y2 != 1, - "Destination badly clipped\n"); - FAIL(!visible, "Destination should be visible\n"); - FAIL(!drm_rect_visible(&src), "Source should be visible\n"); - - /* 2:1 scaling */ - drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16); - drm_rect_init(&dst, 0, 0, 1, 1); - drm_rect_init(&clip, 0, 0, 1, 1); - - visible = drm_rect_clip_scaled(&src, &dst, &clip); - - FAIL(src.x1 != 0 || src.x2 != 2 << 16 || - src.y1 != 0 || src.y2 != 2 << 16, - "Source badly clipped\n"); - FAIL(dst.x1 != 0 || dst.x2 != 1 || - dst.y1 != 0 || dst.y2 != 1, - "Destination badly clipped\n"); - FAIL(!visible, "Destination should be visible\n"); - FAIL(!drm_rect_visible(&src), "Source should be visible\n"); - - /* 1:2 scaling */ - drm_rect_init(&src, 0, 0, 1 << 16, 1 << 16); - drm_rect_init(&dst, 0, 0, 2, 2); - drm_rect_init(&clip, 0, 0, 2, 2); - - visible = drm_rect_clip_scaled(&src, &dst, &clip); - - FAIL(src.x1 != 0 || src.x2 != 1 << 16 || - src.y1 != 0 || src.y2 != 1 << 16, - "Source badly clipped\n"); - FAIL(dst.x1 != 0 || dst.x2 != 2 || - dst.y1 != 0 || dst.y2 != 2, - "Destination badly clipped\n"); - FAIL(!visible, "Destination should be visible\n"); - FAIL(!drm_rect_visible(&src), "Source should be visible\n"); - - return 0; -} - -int igt_drm_rect_clip_scaled_clipped(void *ignored) -{ - struct drm_rect src, dst, clip; - bool visible; - - /* 1:1 scaling top/left clip */ - drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16); - drm_rect_init(&dst, 0, 0, 2, 2); - drm_rect_init(&clip, 0, 0, 1, 1); - - visible = drm_rect_clip_scaled(&src, &dst, &clip); - - FAIL(src.x1 != 0 || src.x2 != 1 << 16 || - src.y1 != 0 || src.y2 != 1 << 16, - "Source badly clipped\n"); - FAIL(dst.x1 != 0 || dst.x2 != 1 || - dst.y1 != 0 || dst.y2 != 1, - "Destination badly clipped\n"); - FAIL(!visible, "Destination should be visible\n"); - FAIL(!drm_rect_visible(&src), "Source should be visible\n"); - - /* 1:1 scaling bottom/right clip */ - drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16); - drm_rect_init(&dst, 0, 0, 2, 2); - drm_rect_init(&clip, 1, 1, 1, 1); - - visible = drm_rect_clip_scaled(&src, &dst, &clip); - - FAIL(src.x1 != 1 << 16 || src.x2 != 2 << 16 || - src.y1 != 1 << 16 || src.y2 != 2 << 16, - "Source badly clipped\n"); - FAIL(dst.x1 != 1 || dst.x2 != 2 || - dst.y1 != 1 || dst.y2 != 2, - "Destination badly clipped\n"); - FAIL(!visible, "Destination should be visible\n"); - FAIL(!drm_rect_visible(&src), "Source should be visible\n"); - - /* 2:1 scaling top/left clip */ - drm_rect_init(&src, 0, 0, 4 << 16, 4 << 16); - drm_rect_init(&dst, 0, 0, 2, 2); - drm_rect_init(&clip, 0, 0, 1, 1); - - visible = drm_rect_clip_scaled(&src, &dst, &clip); - - FAIL(src.x1 != 0 || src.x2 != 2 << 16 || - src.y1 != 0 || src.y2 != 2 << 16, - "Source badly clipped\n"); - FAIL(dst.x1 != 0 || dst.x2 != 1 || - dst.y1 != 0 || dst.y2 != 1, - "Destination badly clipped\n"); - FAIL(!visible, "Destination should be visible\n"); - FAIL(!drm_rect_visible(&src), "Source should be visible\n"); - - /* 2:1 scaling bottom/right clip */ - drm_rect_init(&src, 0, 0, 4 << 16, 4 << 16); - drm_rect_init(&dst, 0, 0, 2, 2); - drm_rect_init(&clip, 1, 1, 1, 1); - - visible = drm_rect_clip_scaled(&src, &dst, &clip); - - FAIL(src.x1 != 2 << 16 || src.x2 != 4 << 16 || - src.y1 != 2 << 16 || src.y2 != 4 << 16, - "Source badly clipped\n"); - FAIL(dst.x1 != 1 || dst.x2 != 2 || - dst.y1 != 1 || dst.y2 != 2, - "Destination badly clipped\n"); - FAIL(!visible, "Destination should be visible\n"); - FAIL(!drm_rect_visible(&src), "Source should be visible\n"); - - /* 1:2 scaling top/left clip */ - drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16); - drm_rect_init(&dst, 0, 0, 4, 4); - drm_rect_init(&clip, 0, 0, 2, 2); - - visible = drm_rect_clip_scaled(&src, &dst, &clip); - - FAIL(src.x1 != 0 || src.x2 != 1 << 16 || - src.y1 != 0 || src.y2 != 1 << 16, - "Source badly clipped\n"); - FAIL(dst.x1 != 0 || dst.x2 != 2 || - dst.y1 != 0 || dst.y2 != 2, - "Destination badly clipped\n"); - FAIL(!visible, "Destination should be visible\n"); - FAIL(!drm_rect_visible(&src), "Source should be visible\n"); - - /* 1:2 scaling bottom/right clip */ - drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16); - drm_rect_init(&dst, 0, 0, 4, 4); - drm_rect_init(&clip, 2, 2, 2, 2); - - visible = drm_rect_clip_scaled(&src, &dst, &clip); - - FAIL(src.x1 != 1 << 16 || src.x2 != 2 << 16 || - src.y1 != 1 << 16 || src.y2 != 2 << 16, - "Source badly clipped\n"); - FAIL(dst.x1 != 2 || dst.x2 != 4 || - dst.y1 != 2 || dst.y2 != 4, - "Destination badly clipped\n"); - FAIL(!visible, "Destination should be visible\n"); - FAIL(!drm_rect_visible(&src), "Source should be visible\n"); - - return 0; -} - -int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored) -{ - struct drm_rect src, dst, clip; - bool visible; - - /* - * 'clip.x2 - dst.x1 >= dst width' could result a negative - * src rectangle width which is no longer expected by the - * code as it's using unsigned types. This could lead to - * the clipped source rectangle appering visible when it - * should have been fully clipped. Make sure both rectangles - * end up invisible. - */ - drm_rect_init(&src, 0, 0, INT_MAX, INT_MAX); - drm_rect_init(&dst, 0, 0, 2, 2); - drm_rect_init(&clip, 3, 3, 1, 1); - - visible = drm_rect_clip_scaled(&src, &dst, &clip); - - FAIL(visible, "Destination should not be visible\n"); - FAIL(drm_rect_visible(&src), "Source should not be visible\n"); - - return 0; -} diff --git a/drivers/gpu/drm/shmobile/Kconfig b/drivers/gpu/drm/shmobile/Kconfig index 288b838a904a..4ec5dc74a6b0 100644 --- a/drivers/gpu/drm/shmobile/Kconfig +++ b/drivers/gpu/drm/shmobile/Kconfig @@ -5,7 +5,7 @@ config DRM_SHMOBILE depends on ARCH_SHMOBILE || COMPILE_TEST select BACKLIGHT_CLASS_DEVICE select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER help Choose this option if you have an SH Mobile chipset. If M is selected the module will be called shmob-drm. diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c index 071a929e9fe3..4624c0aff51f 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c @@ -12,11 +12,10 @@ #include <drm/drm_crtc.h> #include <drm/drm_crtc_helper.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_cma_helper.h> -#include <drm/drm_plane_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_simple_kms_helper.h> #include <drm/drm_vblank.h> @@ -289,18 +288,18 @@ static void shmob_drm_crtc_compute_base(struct shmob_drm_crtc *scrtc, { struct drm_crtc *crtc = &scrtc->crtc; struct drm_framebuffer *fb = crtc->primary->fb; - struct drm_gem_cma_object *gem; + struct drm_gem_dma_object *gem; unsigned int bpp; bpp = scrtc->format->yuv ? 8 : scrtc->format->bpp; - gem = drm_fb_cma_get_gem_obj(fb, 0); - scrtc->dma[0] = gem->paddr + fb->offsets[0] + gem = drm_fb_dma_get_gem_obj(fb, 0); + scrtc->dma[0] = gem->dma_addr + fb->offsets[0] + y * fb->pitches[0] + x * bpp / 8; if (scrtc->format->yuv) { bpp = scrtc->format->bpp - 8; - gem = drm_fb_cma_get_gem_obj(fb, 1); - scrtc->dma[1] = gem->paddr + fb->offsets[1] + gem = drm_fb_dma_get_gem_obj(fb, 1); + scrtc->dma[1] = gem->dma_addr + fb->offsets[1] + y / (bpp == 4 ? 2 : 1) * fb->pitches[1] + x * (bpp == 16 ? 2 : 1); } diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c index 731cbad7520f..3d511fa38913 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c @@ -17,7 +17,7 @@ #include <drm/drm_crtc_helper.h> #include <drm/drm_drv.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_module.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> @@ -126,11 +126,11 @@ static irqreturn_t shmob_drm_irq(int irq, void *arg) return IRQ_HANDLED; } -DEFINE_DRM_GEM_CMA_FOPS(shmob_drm_fops); +DEFINE_DRM_GEM_DMA_FOPS(shmob_drm_fops); static const struct drm_driver shmob_drm_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET, - DRM_GEM_CMA_DRIVER_OPS, + DRM_GEM_DMA_DRIVER_OPS, .fops = &shmob_drm_fops, .name = "shmob-drm", .desc = "Renesas SH Mobile DRM", diff --git a/drivers/gpu/drm/shmobile/shmob_drm_kms.c b/drivers/gpu/drm/shmobile/shmob_drm_kms.c index 68d21be784aa..60a2c8d8a0d9 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_kms.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_kms.c @@ -9,9 +9,8 @@ #include <drm/drm_crtc.h> #include <drm/drm_crtc_helper.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fourcc.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_probe_helper.h> diff --git a/drivers/gpu/drm/shmobile/shmob_drm_kms.h b/drivers/gpu/drm/shmobile/shmob_drm_kms.h index 6ec2b732bb94..0347b1fd2338 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_kms.h +++ b/drivers/gpu/drm/shmobile/shmob_drm_kms.h @@ -12,7 +12,7 @@ #include <linux/types.h> -struct drm_gem_cma_object; +struct drm_gem_dma_object; struct shmob_drm_device; struct shmob_drm_format_info { diff --git a/drivers/gpu/drm/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/shmobile/shmob_drm_plane.c index 4763ea8e1af0..54228424793a 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_plane.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_plane.c @@ -9,10 +9,10 @@ #include <drm/drm_crtc.h> #include <drm/drm_crtc_helper.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include "shmob_drm_drv.h" #include "shmob_drm_kms.h" @@ -41,18 +41,18 @@ static void shmob_drm_plane_compute_base(struct shmob_drm_plane *splane, struct drm_framebuffer *fb, int x, int y) { - struct drm_gem_cma_object *gem; + struct drm_gem_dma_object *gem; unsigned int bpp; bpp = splane->format->yuv ? 8 : splane->format->bpp; - gem = drm_fb_cma_get_gem_obj(fb, 0); - splane->dma[0] = gem->paddr + fb->offsets[0] + gem = drm_fb_dma_get_gem_obj(fb, 0); + splane->dma[0] = gem->dma_addr + fb->offsets[0] + y * fb->pitches[0] + x * bpp / 8; if (splane->format->yuv) { bpp = splane->format->bpp - 8; - gem = drm_fb_cma_get_gem_obj(fb, 1); - splane->dma[1] = gem->paddr + fb->offsets[1] + gem = drm_fb_dma_get_gem_obj(fb, 1); + splane->dma[1] = gem->dma_addr + fb->offsets[1] + y / (bpp == 4 ? 2 : 1) * fb->pitches[1] + x * (bpp == 16 ? 2 : 1); } diff --git a/drivers/gpu/drm/sis/sis_drv.c b/drivers/gpu/drm/sis/sis_drv.c index e35e719cf315..6173020a9bf5 100644 --- a/drivers/gpu/drm/sis/sis_drv.c +++ b/drivers/gpu/drm/sis/sis_drv.c @@ -50,7 +50,7 @@ static int sis_driver_load(struct drm_device *dev, unsigned long chipset) if (dev_priv == NULL) return -ENOMEM; - idr_init(&dev_priv->object_idr); + idr_init_base(&dev_priv->object_idr, 1); dev->dev_private = (void *)dev_priv; dev_priv->chipset = chipset; diff --git a/drivers/gpu/drm/solomon/ssd130x-spi.c b/drivers/gpu/drm/solomon/ssd130x-spi.c index 07802907e39a..19ab4942cb33 100644 --- a/drivers/gpu/drm/solomon/ssd130x-spi.c +++ b/drivers/gpu/drm/solomon/ssd130x-spi.c @@ -18,11 +18,6 @@ struct ssd130x_spi_transport { struct gpio_desc *dc; }; -static const struct regmap_config ssd130x_spi_regmap_config = { - .reg_bits = 8, - .val_bits = 8, -}; - /* * The regmap bus .write handler, it is just a wrapper around spi_write() * but toggling the Data/Command control pin (D/C#). Since for 4-wire SPI @@ -56,17 +51,12 @@ static int ssd130x_spi_read(void *context, const void *reg, size_t reg_size, return -EOPNOTSUPP; } -/* - * A custom bus is needed due the special write that toggles a D/C# pin, - * another option could be to just have a .reg_write() callback but that - * will prevent to do data writes in bulk. - * - * Once the regmap API is extended to support defining a bulk write handler - * in the struct regmap_config, this can be simplified and the bus dropped. - */ -static struct regmap_bus regmap_ssd130x_spi_bus = { +static const struct regmap_config ssd130x_spi_regmap_config = { + .reg_bits = 8, + .val_bits = 8, .write = ssd130x_spi_write, .read = ssd130x_spi_read, + .can_multi_write = true, }; static int ssd130x_spi_probe(struct spi_device *spi) @@ -90,8 +80,7 @@ static int ssd130x_spi_probe(struct spi_device *spi) t->spi = spi; t->dc = dc; - regmap = devm_regmap_init(dev, ®map_ssd130x_spi_bus, t, - &ssd130x_spi_regmap_config); + regmap = devm_regmap_init(dev, NULL, t, &ssd130x_spi_regmap_config); if (IS_ERR(regmap)) return PTR_ERR(regmap); diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c index 5a3e3b78cd9e..94d92b726c34 100644 --- a/drivers/gpu/drm/solomon/ssd130x.c +++ b/drivers/gpu/drm/solomon/ssd130x.c @@ -21,7 +21,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_damage_helper.h> #include <drm/drm_edid.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_format_helper.h> #include <drm/drm_framebuffer.h> @@ -537,11 +536,11 @@ static void ssd130x_clear_screen(struct ssd130x_device *ssd130x) kfree(buf); } -static int ssd130x_fb_blit_rect(struct drm_framebuffer *fb, const struct iosys_map *map, +static int ssd130x_fb_blit_rect(struct drm_framebuffer *fb, const struct iosys_map *vmap, struct drm_rect *rect) { struct ssd130x_device *ssd130x = drm_to_ssd130x(fb->dev); - void *vmap = map->vaddr; /* TODO: Use mapping abstraction properly */ + struct iosys_map dst; unsigned int dst_pitch; int ret = 0; u8 *buf = NULL; @@ -555,7 +554,8 @@ static int ssd130x_fb_blit_rect(struct drm_framebuffer *fb, const struct iosys_m if (!buf) return -ENOMEM; - drm_fb_xrgb8888_to_mono(buf, dst_pitch, vmap, fb, rect); + iosys_map_set_vaddr(&dst, buf); + drm_fb_xrgb8888_to_mono(&dst, &dst_pitch, vmap, fb, rect); ssd130x_update_rect(ssd130x, buf, rect); diff --git a/drivers/gpu/drm/sprd/Kconfig b/drivers/gpu/drm/sprd/Kconfig index 9a9c7ebfc716..e22b780fe822 100644 --- a/drivers/gpu/drm/sprd/Kconfig +++ b/drivers/gpu/drm/sprd/Kconfig @@ -2,7 +2,7 @@ config DRM_SPRD tristate "DRM Support for Unisoc SoCs Platform" depends on ARCH_SPRD || COMPILE_TEST depends on DRM && OF - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_KMS_HELPER select DRM_MIPI_DSI select VIDEOMODE_HELPERS diff --git a/drivers/gpu/drm/sprd/sprd_dpu.c b/drivers/gpu/drm/sprd/sprd_dpu.c index 3664089b6983..88f4259680f1 100644 --- a/drivers/gpu/drm/sprd/sprd_dpu.c +++ b/drivers/gpu/drm/sprd/sprd_dpu.c @@ -19,11 +19,10 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_blend.h> #include <drm/drm_crtc_helper.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> -#include <drm/drm_plane_helper.h> #include "sprd_drm.h" #include "sprd_dpu.h" @@ -324,7 +323,7 @@ static u32 drm_blend_to_dpu(struct drm_plane_state *state) static void sprd_dpu_layer(struct sprd_dpu *dpu, struct drm_plane_state *state) { struct dpu_context *ctx = &dpu->ctx; - struct drm_gem_cma_object *cma_obj; + struct drm_gem_dma_object *dma_obj; struct drm_framebuffer *fb = state->fb; u32 addr, size, offset, pitch, blend, format, rotation; u32 src_x = state->src_x >> 16; @@ -341,8 +340,8 @@ static void sprd_dpu_layer(struct sprd_dpu *dpu, struct drm_plane_state *state) size = (src_w & 0xffff) | (src_h << 16); for (i = 0; i < fb->format->num_planes; i++) { - cma_obj = drm_fb_cma_get_gem_obj(fb, i); - addr = cma_obj->paddr + fb->offsets[i]; + dma_obj = drm_fb_dma_get_gem_obj(fb, i); + addr = dma_obj->dma_addr + fb->offsets[i]; if (i == 0) layer_reg_wr(ctx, REG_LAY_BASE_ADDR0, addr, index); @@ -524,8 +523,8 @@ static int sprd_plane_atomic_check(struct drm_plane *plane, return PTR_ERR(crtc_state); return drm_atomic_helper_check_plane_state(plane_state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, true, true); } diff --git a/drivers/gpu/drm/sprd/sprd_drm.c b/drivers/gpu/drm/sprd/sprd_drm.c index b8fc1c6a0cb8..9d42f17a5734 100644 --- a/drivers/gpu/drm/sprd/sprd_drm.c +++ b/drivers/gpu/drm/sprd/sprd_drm.c @@ -13,7 +13,7 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_drv.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_of.h> #include <drm/drm_probe_helper.h> @@ -48,14 +48,14 @@ static void sprd_drm_mode_config_init(struct drm_device *drm) drm->mode_config.helper_private = &sprd_drm_mode_config_helper; } -DEFINE_DRM_GEM_CMA_FOPS(sprd_drm_fops); +DEFINE_DRM_GEM_DMA_FOPS(sprd_drm_fops); static struct drm_driver sprd_drm_drv = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .fops = &sprd_drm_fops, /* GEM Operations */ - DRM_GEM_CMA_DRIVER_OPS, + DRM_GEM_DMA_DRIVER_OPS, .name = DRIVER_NAME, .desc = DRIVER_DESC, diff --git a/drivers/gpu/drm/sti/Kconfig b/drivers/gpu/drm/sti/Kconfig index 246a94afbe74..f2a880c48485 100644 --- a/drivers/gpu/drm/sti/Kconfig +++ b/drivers/gpu/drm/sti/Kconfig @@ -4,7 +4,7 @@ config DRM_STI depends on OF && DRM && (ARCH_STI || ARCH_MULTIPLATFORM) select RESET_CONTROLLER select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_PANEL select FW_LOADER select SND_SOC_HDMI_CODEC if SND_SOC diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c index 409795786f03..3c7154f2d5f3 100644 --- a/drivers/gpu/drm/sti/sti_crtc.c +++ b/drivers/gpu/drm/sti/sti_crtc.c @@ -11,7 +11,6 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_device.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c index 1e9bd4241f10..db0a1eb53532 100644 --- a/drivers/gpu/drm/sti/sti_cursor.c +++ b/drivers/gpu/drm/sti/sti_cursor.c @@ -11,9 +11,9 @@ #include <drm/drm_atomic.h> #include <drm/drm_device.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include "sti_compositor.h" #include "sti_cursor.h" @@ -243,8 +243,8 @@ static int sti_cursor_atomic_check(struct drm_plane *drm_plane, } } - if (!drm_fb_cma_get_gem_obj(fb, 0)) { - DRM_ERROR("Can't get CMA GEM object for fb\n"); + if (!drm_fb_dma_get_gem_obj(fb, 0)) { + DRM_ERROR("Can't get DMA GEM object for fb\n"); return -EINVAL; } @@ -267,7 +267,7 @@ static void sti_cursor_atomic_update(struct drm_plane *drm_plane, struct drm_framebuffer *fb = newstate->fb; struct drm_display_mode *mode; int dst_x, dst_y; - struct drm_gem_cma_object *cma_obj; + struct drm_gem_dma_object *dma_obj; u32 y, x; u32 val; @@ -278,10 +278,10 @@ static void sti_cursor_atomic_update(struct drm_plane *drm_plane, dst_x = newstate->crtc_x; dst_y = newstate->crtc_y; - cma_obj = drm_fb_cma_get_gem_obj(fb, 0); + dma_obj = drm_fb_dma_get_gem_obj(fb, 0); /* Convert ARGB8888 to CLUT8 */ - sti_cursor_argb8888_to_clut8(cursor, (u32 *)cma_obj->vaddr); + sti_cursor_argb8888_to_clut8(cursor, (u32 *)dma_obj->vaddr); /* AWS and AWE depend on the mode */ y = sti_vtg_get_line_number(*mode, 0); diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c index d858209cf8de..7abf010a3293 100644 --- a/drivers/gpu/drm/sti/sti_drv.c +++ b/drivers/gpu/drm/sti/sti_drv.c @@ -14,9 +14,8 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_debugfs.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_of.h> #include <drm/drm_probe_helper.h> @@ -128,12 +127,12 @@ static void sti_mode_config_init(struct drm_device *dev) dev->mode_config.normalize_zpos = true; } -DEFINE_DRM_GEM_CMA_FOPS(sti_driver_fops); +DEFINE_DRM_GEM_DMA_FOPS(sti_driver_fops); static const struct drm_driver sti_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, .fops = &sti_driver_fops, - DRM_GEM_CMA_DRIVER_OPS, + DRM_GEM_DMA_DRIVER_OPS, .debugfs_init = sti_drm_dbg_init, diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c index af783f599306..43c72c2604a0 100644 --- a/drivers/gpu/drm/sti/sti_gdp.c +++ b/drivers/gpu/drm/sti/sti_gdp.c @@ -12,10 +12,10 @@ #include <drm/drm_atomic.h> #include <drm/drm_device.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include "sti_compositor.h" #include "sti_gdp.h" @@ -658,8 +658,8 @@ static int sti_gdp_atomic_check(struct drm_plane *drm_plane, return -EINVAL; } - if (!drm_fb_cma_get_gem_obj(fb, 0)) { - DRM_ERROR("Can't get CMA GEM object for fb\n"); + if (!drm_fb_dma_get_gem_obj(fb, 0)) { + DRM_ERROR("Can't get DMA GEM object for fb\n"); return -EINVAL; } @@ -714,7 +714,7 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane, struct drm_display_mode *mode; int dst_x, dst_y, dst_w, dst_h; int src_x, src_y, src_w, src_h; - struct drm_gem_cma_object *cma_obj; + struct drm_gem_dma_object *dma_obj; struct sti_gdp_node_list *list; struct sti_gdp_node_list *curr_list; struct sti_gdp_node *top_field, *btm_field; @@ -778,15 +778,15 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane, top_field->gam_gdp_ctl |= sti_gdp_get_alpharange(format); top_field->gam_gdp_ppt &= ~GAM_GDP_PPT_IGNORE; - cma_obj = drm_fb_cma_get_gem_obj(fb, 0); + dma_obj = drm_fb_dma_get_gem_obj(fb, 0); DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id, (char *)&fb->format->format, - (unsigned long)cma_obj->paddr); + (unsigned long) dma_obj->dma_addr); /* pixel memory location */ bpp = fb->format->cpp[0]; - top_field->gam_gdp_pml = (u32)cma_obj->paddr + fb->offsets[0]; + top_field->gam_gdp_pml = (u32) dma_obj->dma_addr + fb->offsets[0]; top_field->gam_gdp_pml += src_x * bpp; top_field->gam_gdp_pml += src_y * fb->pitches[0]; @@ -831,7 +831,7 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane, dev_dbg(gdp->dev, "Current NVN:0x%X\n", readl(gdp->regs + GAM_GDP_NVN_OFFSET)); dev_dbg(gdp->dev, "Posted buff: %lx current buff: %x\n", - (unsigned long)cma_obj->paddr, + (unsigned long) dma_obj->dma_addr, readl(gdp->regs + GAM_GDP_PML_OFFSET)); if (!curr_list) { diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c index 271982080437..02b77279f6e4 100644 --- a/drivers/gpu/drm/sti/sti_hqvdp.c +++ b/drivers/gpu/drm/sti/sti_hqvdp.c @@ -16,10 +16,10 @@ #include <drm/drm_atomic.h> #include <drm/drm_device.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include "sti_compositor.h" #include "sti_drv.h" @@ -1055,8 +1055,8 @@ static int sti_hqvdp_atomic_check(struct drm_plane *drm_plane, return -EINVAL; } - if (!drm_fb_cma_get_gem_obj(fb, 0)) { - DRM_ERROR("Can't get CMA GEM object for fb\n"); + if (!drm_fb_dma_get_gem_obj(fb, 0)) { + DRM_ERROR("Can't get DMA GEM object for fb\n"); return -EINVAL; } @@ -1124,7 +1124,7 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane, struct drm_display_mode *mode; int dst_x, dst_y, dst_w, dst_h; int src_x, src_y, src_w, src_h; - struct drm_gem_cma_object *cma_obj; + struct drm_gem_dma_object *dma_obj; struct sti_hqvdp_cmd *cmd; int scale_h, scale_v; int cmd_offset; @@ -1178,15 +1178,15 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane, cmd->iqi.sat_gain = IQI_SAT_GAIN_DFLT; cmd->iqi.pxf_conf = IQI_PXF_CONF_DFLT; - cma_obj = drm_fb_cma_get_gem_obj(fb, 0); + dma_obj = drm_fb_dma_get_gem_obj(fb, 0); DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id, (char *)&fb->format->format, - (unsigned long)cma_obj->paddr); + (unsigned long) dma_obj->dma_addr); /* Buffer planes address */ - cmd->top.current_luma = (u32)cma_obj->paddr + fb->offsets[0]; - cmd->top.current_chroma = (u32)cma_obj->paddr + fb->offsets[1]; + cmd->top.current_luma = (u32) dma_obj->dma_addr + fb->offsets[0]; + cmd->top.current_chroma = (u32) dma_obj->dma_addr + fb->offsets[1]; /* Pitches */ cmd->top.luma_processed_pitch = fb->pitches[0]; diff --git a/drivers/gpu/drm/sti/sti_plane.c b/drivers/gpu/drm/sti/sti_plane.c index c74b524663ab..29e669ccec5b 100644 --- a/drivers/gpu/drm/sti/sti_plane.c +++ b/drivers/gpu/drm/sti/sti_plane.c @@ -9,10 +9,9 @@ #include <linux/types.h> #include <drm/drm_blend.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include "sti_compositor.h" #include "sti_drv.h" diff --git a/drivers/gpu/drm/sti/sti_plane.h b/drivers/gpu/drm/sti/sti_plane.h index 8e33e629d9b0..2c0156bede9c 100644 --- a/drivers/gpu/drm/sti/sti_plane.h +++ b/drivers/gpu/drm/sti/sti_plane.h @@ -8,7 +8,6 @@ #define _STI_PLANE_H_ #include <drm/drm_atomic_helper.h> -#include <drm/drm_plane_helper.h> #define to_sti_plane(x) container_of(x, struct sti_plane, drm_plane) diff --git a/drivers/gpu/drm/stm/Kconfig b/drivers/gpu/drm/stm/Kconfig index e0379488cd0d..ded72f879482 100644 --- a/drivers/gpu/drm/stm/Kconfig +++ b/drivers/gpu/drm/stm/Kconfig @@ -3,7 +3,7 @@ config DRM_STM tristate "DRM Support for STMicroelectronics SoC Series" depends on DRM && (ARCH_STM32 || ARCH_MULTIPLATFORM) select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_PANEL_BRIDGE select VIDEOMODE_HELPERS select FB_PROVIDE_GET_FB_UNMAPPED_AREA if FB diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c index c63945dc2260..d7914f5122df 100644 --- a/drivers/gpu/drm/stm/drv.c +++ b/drivers/gpu/drm/stm/drv.c @@ -18,9 +18,8 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_module.h> #include <drm/drm_probe_helper.h> @@ -37,7 +36,7 @@ static const struct drm_mode_config_funcs drv_mode_config_funcs = { .atomic_commit = drm_atomic_helper_commit, }; -static int stm_gem_cma_dumb_create(struct drm_file *file, +static int stm_gem_dma_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args) { @@ -50,10 +49,10 @@ static int stm_gem_cma_dumb_create(struct drm_file *file, args->pitch = roundup(min_pitch, 128); args->height = roundup(args->height, 4); - return drm_gem_cma_dumb_create_internal(file, dev, args); + return drm_gem_dma_dumb_create_internal(file, dev, args); } -DEFINE_DRM_GEM_CMA_FOPS(drv_driver_fops); +DEFINE_DRM_GEM_DMA_FOPS(drv_driver_fops); static const struct drm_driver drv_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, @@ -64,7 +63,7 @@ static const struct drm_driver drv_driver = { .minor = 0, .patchlevel = 0, .fops = &drv_driver_fops, - DRM_GEM_CMA_DRIVER_OPS_WITH_DUMB_CREATE(stm_gem_cma_dumb_create), + DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(stm_gem_dma_dumb_create), }; static int drv_load(struct drm_device *ddev) diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c index da7a0a183b27..03c6becda795 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c @@ -28,13 +28,12 @@ #include <drm/drm_bridge.h> #include <drm/drm_device.h> #include <drm/drm_edid.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_of.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_simple_kms_helper.h> #include <drm/drm_vblank.h> @@ -1347,7 +1346,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, } /* Sets the FB address */ - paddr = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 0); + paddr = (u32)drm_fb_dma_get_gem_addr(fb, newstate, 0); if (newstate->rotation & DRM_MODE_REFLECT_X) paddr += (fb->format->cpp[0] * (x1 - x0 + 1)) - 1; @@ -1381,7 +1380,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, case DRM_FORMAT_NV12: case DRM_FORMAT_NV21: /* Configure the auxiliary frame buffer address 0 */ - paddr1 = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 1); + paddr1 = (u32)drm_fb_dma_get_gem_addr(fb, newstate, 1); if (newstate->rotation & DRM_MODE_REFLECT_X) paddr1 += ((fb->format->cpp[1] * (x1 - x0 + 1)) >> 1) - 1; @@ -1393,8 +1392,8 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, break; case DRM_FORMAT_YUV420: /* Configure the auxiliary frame buffer address 0 & 1 */ - paddr1 = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 1); - paddr2 = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 2); + paddr1 = (u32)drm_fb_dma_get_gem_addr(fb, newstate, 1); + paddr2 = (u32)drm_fb_dma_get_gem_addr(fb, newstate, 2); if (newstate->rotation & DRM_MODE_REFLECT_X) { paddr1 += ((fb->format->cpp[1] * (x1 - x0 + 1)) >> 1) - 1; @@ -1411,8 +1410,8 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, break; case DRM_FORMAT_YVU420: /* Configure the auxiliary frame buffer address 0 & 1 */ - paddr1 = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 2); - paddr2 = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 1); + paddr1 = (u32)drm_fb_dma_get_gem_addr(fb, newstate, 2); + paddr2 = (u32)drm_fb_dma_get_gem_addr(fb, newstate, 1); if (newstate->rotation & DRM_MODE_REFLECT_X) { paddr1 += ((fb->format->cpp[1] * (x1 - x0 + 1)) >> 1) - 1; diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig index 3a43c436c74a..4741d9f6544c 100644 --- a/drivers/gpu/drm/sun4i/Kconfig +++ b/drivers/gpu/drm/sun4i/Kconfig @@ -3,7 +3,7 @@ config DRM_SUN4I tristate "DRM Support for Allwinner A10 Display Engine" depends on DRM && COMMON_CLK depends on ARCH_SUNXI || COMPILE_TEST - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_KMS_HELPER select DRM_PANEL select REGMAP_MMIO @@ -16,23 +16,25 @@ config DRM_SUN4I if DRM_SUN4I config DRM_SUN4I_HDMI - tristate "Allwinner A10 HDMI Controller Support" + tristate "Allwinner A10/A10s/A20/A31 HDMI Controller Support" + depends on ARM || COMPILE_TEST default DRM_SUN4I help - Choose this option if you have an Allwinner SoC with an HDMI - controller. + Choose this option if you have an Allwinner A10/A10s/A20/A31 + SoC with an HDMI controller. config DRM_SUN4I_HDMI_CEC - bool "Allwinner A10 HDMI CEC Support" + bool "Allwinner A10/A10s/A20/A31 HDMI CEC Support" depends on DRM_SUN4I_HDMI select CEC_CORE select CEC_PIN help - Choose this option if you have an Allwinner SoC with an HDMI - controller and want to use CEC. + Choose this option if you have an Allwinner A10/A10s/A20/A31 + SoC with an HDMI controller and want to use CEC. config DRM_SUN4I_BACKEND tristate "Support for Allwinner A10 Display Engine Backend" + depends on ARM || COMPILE_TEST default DRM_SUN4I help Choose this option if you have an Allwinner SoC with the @@ -41,8 +43,8 @@ config DRM_SUN4I_BACKEND selected the module will be called sun4i-backend. config DRM_SUN6I_DSI - tristate "Allwinner A31 MIPI-DSI Controller Support" - default MACH_SUN8I + tristate "Allwinner A31/A64 MIPI-DSI Controller Support" + default DRM_SUN4I select CRC_CCITT select DRM_MIPI_DSI select RESET_CONTROLLER @@ -55,15 +57,17 @@ config DRM_SUN6I_DSI config DRM_SUN8I_DW_HDMI tristate "Support for Allwinner version of DesignWare HDMI" depends on DRM_SUN4I + default DRM_SUN4I select DRM_DW_HDMI help Choose this option if you have an Allwinner SoC with the - DesignWare HDMI controller with custom HDMI PHY. If M is + DesignWare HDMI controller. SoCs that support HDMI and + have a Display Engine 2.0 contain this controller. If M is selected the module will be called sun8i_dw_hdmi. config DRM_SUN8I_MIXER tristate "Support for Allwinner Display Engine 2.0 Mixer" - default MACH_SUN8I + default DRM_SUN4I help Choose this option if you have an Allwinner SoC with the Allwinner Display Engine 2.0, which has a mixer to do some @@ -75,6 +79,6 @@ config DRM_SUN8I_TCON_TOP default DRM_SUN4I if DRM_SUN8I_MIXER!=n help TCON TOP is responsible for configuring display pipeline for - HTMI, TVE and LCD. + HDMI, TVE and LCD. endif diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index 287e8c4bbaea..38070fc261f3 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -19,11 +19,10 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_blend.h> #include <drm/drm_crtc.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_cma_helper.h> -#include <drm/drm_plane_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_probe_helper.h> #include "sun4i_backend.h" @@ -330,7 +329,7 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, struct drm_plane_state *state = plane->state; struct drm_framebuffer *fb = state->fb; u32 lo_paddr, hi_paddr; - dma_addr_t paddr; + dma_addr_t dma_addr; /* Set the line width */ DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8); @@ -339,21 +338,21 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, fb->pitches[0] * 8); /* Get the start of the displayed memory */ - paddr = drm_fb_cma_get_gem_addr(fb, state, 0); - DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr); + dma_addr = drm_fb_dma_get_gem_addr(fb, state, 0); + DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &dma_addr); if (fb->format->is_yuv) - return sun4i_backend_update_yuv_buffer(backend, fb, paddr); + return sun4i_backend_update_yuv_buffer(backend, fb, dma_addr); /* Write the 32 lower bits of the address (in bits) */ - lo_paddr = paddr << 3; + lo_paddr = dma_addr << 3; DRM_DEBUG_DRIVER("Setting address lower bits to 0x%x\n", lo_paddr); regmap_write(backend->engine.regs, SUN4I_BACKEND_LAYFB_L32ADD_REG(layer), lo_paddr); /* And the upper bits */ - hi_paddr = paddr >> 29; + hi_paddr = dma_addr >> 29; DRM_DEBUG_DRIVER("Setting address high bits to 0x%x\n", hi_paddr); regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_LAYFB_H4ADD_REG, SUN4I_BACKEND_LAYFB_H4ADD_MSK(layer), diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index 6eb1aabdb161..d06ffd99d86e 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -17,9 +17,8 @@ #include <drm/drm_aperture.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_module.h> #include <drm/drm_of.h> #include <drm/drm_probe_helper.h> @@ -38,10 +37,10 @@ static int drm_sun4i_gem_dumb_create(struct drm_file *file_priv, /* The hardware only allows even pitches for YUV buffers. */ args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8), 2); - return drm_gem_cma_dumb_create_internal(file_priv, drm, args); + return drm_gem_dma_dumb_create_internal(file_priv, drm, args); } -DEFINE_DRM_GEM_CMA_FOPS(sun4i_drv_fops); +DEFINE_DRM_GEM_DMA_FOPS(sun4i_drv_fops); static const struct drm_driver sun4i_drv_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, @@ -55,7 +54,7 @@ static const struct drm_driver sun4i_drv_driver = { .minor = 0, /* GEM Operations */ - DRM_GEM_CMA_DRIVER_OPS_WITH_DUMB_CREATE(drm_sun4i_gem_dumb_create), + DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(drm_sun4i_gem_dumb_create), }; static int sun4i_drv_bind(struct device *dev) diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.c b/drivers/gpu/drm/sun4i/sun4i_frontend.c index 462fae73eae9..799ab7460ae5 100644 --- a/drivers/gpu/drm/sun4i/sun4i_frontend.c +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c @@ -14,10 +14,10 @@ #include <linux/reset.h> #include <drm/drm_device.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_plane.h> #include "sun4i_drv.h" @@ -160,7 +160,7 @@ void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend, struct drm_framebuffer *fb = state->fb; unsigned int strides[3] = {}; - dma_addr_t paddr; + dma_addr_t dma_addr; bool swap; if (fb->modifier == DRM_FORMAT_MOD_ALLWINNER_TILED) { @@ -221,22 +221,24 @@ void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend, swap = sun4i_frontend_format_chroma_requires_swap(fb->format->format); /* Set the physical address of the buffer in memory */ - paddr = drm_fb_cma_get_gem_addr(fb, state, 0); - DRM_DEBUG_DRIVER("Setting buffer #0 address to %pad\n", &paddr); - regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, paddr); + dma_addr = drm_fb_dma_get_gem_addr(fb, state, 0); + DRM_DEBUG_DRIVER("Setting buffer #0 address to %pad\n", &dma_addr); + regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, dma_addr); if (fb->format->num_planes > 1) { - paddr = drm_fb_cma_get_gem_addr(fb, state, swap ? 2 : 1); - DRM_DEBUG_DRIVER("Setting buffer #1 address to %pad\n", &paddr); + dma_addr = drm_fb_dma_get_gem_addr(fb, state, swap ? 2 : 1); + DRM_DEBUG_DRIVER("Setting buffer #1 address to %pad\n", + &dma_addr); regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR1_REG, - paddr); + dma_addr); } if (fb->format->num_planes > 2) { - paddr = drm_fb_cma_get_gem_addr(fb, state, swap ? 1 : 2); - DRM_DEBUG_DRIVER("Setting buffer #2 address to %pad\n", &paddr); + dma_addr = drm_fb_dma_get_gem_addr(fb, state, swap ? 1 : 2); + DRM_DEBUG_DRIVER("Setting buffer #2 address to %pad\n", + &dma_addr); regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR2_REG, - paddr); + dma_addr); } } EXPORT_SYMBOL(sun4i_frontend_update_buffer); diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c index 648dd0b5b116..98f3176366c0 100644 --- a/drivers/gpu/drm/sun4i/sun4i_layer.c +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c @@ -10,7 +10,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_blend.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_plane_helper.h> #include "sun4i_backend.h" #include "sun4i_frontend.h" diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c index 648b38a73066..bafee05f6b24 100644 --- a/drivers/gpu/drm/sun4i/sun8i_mixer.c +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c @@ -16,10 +16,8 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_cma_helper.h> -#include <drm/drm_plane_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_probe_helper.h> #include "sun4i_drv.h" diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c index 36da962de394..ca75ca0835a6 100644 --- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c +++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c @@ -13,12 +13,11 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_blend.h> #include <drm/drm_crtc.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> -#include <drm/drm_plane_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_probe_helper.h> #include "sun8i_mixer.h" @@ -193,25 +192,25 @@ static int sun8i_ui_layer_update_buffer(struct sun8i_mixer *mixer, int channel, { struct drm_plane_state *state = plane->state; struct drm_framebuffer *fb = state->fb; - struct drm_gem_cma_object *gem; - dma_addr_t paddr; + struct drm_gem_dma_object *gem; + dma_addr_t dma_addr; u32 ch_base; int bpp; ch_base = sun8i_channel_base(mixer, channel); /* Get the physical address of the buffer in memory */ - gem = drm_fb_cma_get_gem_obj(fb, 0); + gem = drm_fb_dma_get_gem_obj(fb, 0); - DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr); + DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->dma_addr); /* Compute the start of the displayed memory */ bpp = fb->format->cpp[0]; - paddr = gem->paddr + fb->offsets[0]; + dma_addr = gem->dma_addr + fb->offsets[0]; /* Fixup framebuffer address for src coordinates */ - paddr += (state->src.x1 >> 16) * bpp; - paddr += (state->src.y1 >> 16) * fb->pitches[0]; + dma_addr += (state->src.x1 >> 16) * bpp; + dma_addr += (state->src.y1 >> 16) * fb->pitches[0]; /* Set the line width */ DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]); @@ -219,11 +218,11 @@ static int sun8i_ui_layer_update_buffer(struct sun8i_mixer *mixer, int channel, SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch_base, overlay), fb->pitches[0]); - DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr); + DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &dma_addr); regmap_write(mixer->engine.regs, SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch_base, overlay), - lower_32_bits(paddr)); + lower_32_bits(dma_addr)); return 0; } @@ -246,8 +245,8 @@ static int sun8i_ui_layer_atomic_check(struct drm_plane *plane, if (WARN_ON(!crtc_state)) return -EINVAL; - min_scale = DRM_PLANE_HELPER_NO_SCALING; - max_scale = DRM_PLANE_HELPER_NO_SCALING; + min_scale = DRM_PLANE_NO_SCALING; + max_scale = DRM_PLANE_NO_SCALING; if (layer->mixer->cfg->scaler_mask & BIT(layer->channel)) { min_scale = SUN8I_UI_SCALER_SCALE_MIN; diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c index 1fee6499bdd3..f9c0a56d3a14 100644 --- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c +++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c @@ -7,11 +7,10 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_blend.h> #include <drm/drm_crtc.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> -#include <drm/drm_plane_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_probe_helper.h> #include "sun8i_csc.h" @@ -309,9 +308,9 @@ static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel, struct drm_plane_state *state = plane->state; struct drm_framebuffer *fb = state->fb; const struct drm_format_info *format = fb->format; - struct drm_gem_cma_object *gem; + struct drm_gem_dma_object *gem; u32 dx, dy, src_x, src_y; - dma_addr_t paddr; + dma_addr_t dma_addr; u32 ch_base; int i; @@ -323,12 +322,12 @@ static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel, for (i = 0; i < format->num_planes; i++) { /* Get the physical address of the buffer in memory */ - gem = drm_fb_cma_get_gem_obj(fb, i); + gem = drm_fb_dma_get_gem_obj(fb, i); - DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr); + DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->dma_addr); /* Compute the start of the displayed memory */ - paddr = gem->paddr + fb->offsets[i]; + dma_addr = gem->dma_addr + fb->offsets[i]; dx = src_x; dy = src_y; @@ -339,8 +338,8 @@ static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel, } /* Fixup framebuffer address for src coordinates */ - paddr += dx * format->cpp[i]; - paddr += dy * fb->pitches[i]; + dma_addr += dx * format->cpp[i]; + dma_addr += dy * fb->pitches[i]; /* Set the line width */ DRM_DEBUG_DRIVER("Layer %d. line width: %d bytes\n", @@ -351,12 +350,12 @@ static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel, fb->pitches[i]); DRM_DEBUG_DRIVER("Setting %d. buffer address to %pad\n", - i + 1, &paddr); + i + 1, &dma_addr); regmap_write(mixer->engine.regs, SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(ch_base, overlay, i), - lower_32_bits(paddr)); + lower_32_bits(dma_addr)); } return 0; @@ -380,8 +379,8 @@ static int sun8i_vi_layer_atomic_check(struct drm_plane *plane, if (WARN_ON(!crtc_state)) return -EINVAL; - min_scale = DRM_PLANE_HELPER_NO_SCALING; - max_scale = DRM_PLANE_HELPER_NO_SCALING; + min_scale = DRM_PLANE_NO_SCALING; + max_scale = DRM_PLANE_NO_SCALING; if (layer->mixer->cfg->scaler_mask & BIT(layer->channel)) { min_scale = SUN8I_VI_SCALER_SCALE_MIN; diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 747abafb6a5c..bd0f60704467 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -26,7 +26,6 @@ #include <drm/drm_debugfs.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_vblank.h> #include "dc.h" diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c index ed828de5ac01..9291209154a7 100644 --- a/drivers/gpu/drm/tegra/fb.c +++ b/drivers/gpu/drm/tegra/fb.c @@ -3,7 +3,7 @@ * Copyright (C) 2012-2013 Avionic Design GmbH * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. * - * Based on the KMS/FB CMA helpers + * Based on the KMS/FB DMA helpers * Copyright (C) 2012 Analog Devices Inc. */ diff --git a/drivers/gpu/drm/tegra/plane.c b/drivers/gpu/drm/tegra/plane.c index ca9f03e3675b..10090116895f 100644 --- a/drivers/gpu/drm/tegra/plane.c +++ b/drivers/gpu/drm/tegra/plane.c @@ -12,7 +12,6 @@ #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_plane_helper.h> #include "dc.h" #include "plane.h" diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile index 2c8273796d9d..91b70f7d2769 100644 --- a/drivers/gpu/drm/tests/Makefile +++ b/drivers/gpu/drm/tests/Makefile @@ -1,3 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_DRM_KUNIT_TEST) += drm_format_helper_test.o +obj-$(CONFIG_DRM_KUNIT_TEST) += drm_format_helper_test.o drm_damage_helper_test.o \ + drm_cmdline_parser_test.o drm_rect_test.o drm_format_test.o drm_plane_helper_test.o \ + drm_dp_mst_helper_test.o drm_framebuffer_test.o drm_buddy_test.o drm_mm_test.o diff --git a/drivers/gpu/drm/tests/drm_buddy_test.c b/drivers/gpu/drm/tests/drm_buddy_test.c new file mode 100644 index 000000000000..d76f83833e75 --- /dev/null +++ b/drivers/gpu/drm/tests/drm_buddy_test.c @@ -0,0 +1,756 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2019 Intel Corporation + * Copyright © 2022 MaÃra Canal <mairacanal@riseup.net> + */ + +#include <kunit/test.h> + +#include <linux/prime_numbers.h> +#include <linux/sched/signal.h> + +#include <drm/drm_buddy.h> + +#include "../lib/drm_random.h" + +#define IGT_TIMEOUT(name__) \ + unsigned long name__ = jiffies + MAX_SCHEDULE_TIMEOUT + +static unsigned int random_seed; + +static inline u64 get_size(int order, u64 chunk_size) +{ + return (1 << order) * chunk_size; +} + +__printf(2, 3) +static bool __igt_timeout(unsigned long timeout, const char *fmt, ...) +{ + va_list va; + + if (!signal_pending(current)) { + cond_resched(); + if (time_before(jiffies, timeout)) + return false; + } + + if (fmt) { + va_start(va, fmt); + vprintk(fmt, va); + va_end(va); + } + + return true; +} + +static void __igt_dump_block(struct kunit *test, struct drm_buddy *mm, + struct drm_buddy_block *block, bool buddy) +{ + kunit_err(test, "block info: header=%llx, state=%u, order=%d, offset=%llx size=%llx root=%d buddy=%d\n", + block->header, drm_buddy_block_state(block), + drm_buddy_block_order(block), drm_buddy_block_offset(block), + drm_buddy_block_size(mm, block), !block->parent, buddy); +} + +static void igt_dump_block(struct kunit *test, struct drm_buddy *mm, + struct drm_buddy_block *block) +{ + struct drm_buddy_block *buddy; + + __igt_dump_block(test, mm, block, false); + + buddy = drm_get_buddy(block); + if (buddy) + __igt_dump_block(test, mm, buddy, true); +} + +static int igt_check_block(struct kunit *test, struct drm_buddy *mm, + struct drm_buddy_block *block) +{ + struct drm_buddy_block *buddy; + unsigned int block_state; + u64 block_size; + u64 offset; + int err = 0; + + block_state = drm_buddy_block_state(block); + + if (block_state != DRM_BUDDY_ALLOCATED && + block_state != DRM_BUDDY_FREE && block_state != DRM_BUDDY_SPLIT) { + kunit_err(test, "block state mismatch\n"); + err = -EINVAL; + } + + block_size = drm_buddy_block_size(mm, block); + offset = drm_buddy_block_offset(block); + + if (block_size < mm->chunk_size) { + kunit_err(test, "block size smaller than min size\n"); + err = -EINVAL; + } + + if (!is_power_of_2(block_size)) { + kunit_err(test, "block size not power of two\n"); + err = -EINVAL; + } + + if (!IS_ALIGNED(block_size, mm->chunk_size)) { + kunit_err(test, "block size not aligned to min size\n"); + err = -EINVAL; + } + + if (!IS_ALIGNED(offset, mm->chunk_size)) { + kunit_err(test, "block offset not aligned to min size\n"); + err = -EINVAL; + } + + if (!IS_ALIGNED(offset, block_size)) { + kunit_err(test, "block offset not aligned to block size\n"); + err = -EINVAL; + } + + buddy = drm_get_buddy(block); + + if (!buddy && block->parent) { + kunit_err(test, "buddy has gone fishing\n"); + err = -EINVAL; + } + + if (buddy) { + if (drm_buddy_block_offset(buddy) != (offset ^ block_size)) { + kunit_err(test, "buddy has wrong offset\n"); + err = -EINVAL; + } + + if (drm_buddy_block_size(mm, buddy) != block_size) { + kunit_err(test, "buddy size mismatch\n"); + err = -EINVAL; + } + + if (drm_buddy_block_state(buddy) == block_state && + block_state == DRM_BUDDY_FREE) { + kunit_err(test, "block and its buddy are free\n"); + err = -EINVAL; + } + } + + return err; +} + +static int igt_check_blocks(struct kunit *test, struct drm_buddy *mm, + struct list_head *blocks, u64 expected_size, bool is_contiguous) +{ + struct drm_buddy_block *block; + struct drm_buddy_block *prev; + u64 total; + int err = 0; + + block = NULL; + prev = NULL; + total = 0; + + list_for_each_entry(block, blocks, link) { + err = igt_check_block(test, mm, block); + + if (!drm_buddy_block_is_allocated(block)) { + kunit_err(test, "block not allocated\n"); + err = -EINVAL; + } + + if (is_contiguous && prev) { + u64 prev_block_size; + u64 prev_offset; + u64 offset; + + prev_offset = drm_buddy_block_offset(prev); + prev_block_size = drm_buddy_block_size(mm, prev); + offset = drm_buddy_block_offset(block); + + if (offset != (prev_offset + prev_block_size)) { + kunit_err(test, "block offset mismatch\n"); + err = -EINVAL; + } + } + + if (err) + break; + + total += drm_buddy_block_size(mm, block); + prev = block; + } + + if (!err) { + if (total != expected_size) { + kunit_err(test, "size mismatch, expected=%llx, found=%llx\n", + expected_size, total); + err = -EINVAL; + } + return err; + } + + if (prev) { + kunit_err(test, "prev block, dump:\n"); + igt_dump_block(test, mm, prev); + } + + kunit_err(test, "bad block, dump:\n"); + igt_dump_block(test, mm, block); + + return err; +} + +static int igt_check_mm(struct kunit *test, struct drm_buddy *mm) +{ + struct drm_buddy_block *root; + struct drm_buddy_block *prev; + unsigned int i; + u64 total; + int err = 0; + + if (!mm->n_roots) { + kunit_err(test, "n_roots is zero\n"); + return -EINVAL; + } + + if (mm->n_roots != hweight64(mm->size)) { + kunit_err(test, "n_roots mismatch, n_roots=%u, expected=%lu\n", + mm->n_roots, hweight64(mm->size)); + return -EINVAL; + } + + root = NULL; + prev = NULL; + total = 0; + + for (i = 0; i < mm->n_roots; ++i) { + struct drm_buddy_block *block; + unsigned int order; + + root = mm->roots[i]; + if (!root) { + kunit_err(test, "root(%u) is NULL\n", i); + err = -EINVAL; + break; + } + + err = igt_check_block(test, mm, root); + + if (!drm_buddy_block_is_free(root)) { + kunit_err(test, "root not free\n"); + err = -EINVAL; + } + + order = drm_buddy_block_order(root); + + if (!i) { + if (order != mm->max_order) { + kunit_err(test, "max order root missing\n"); + err = -EINVAL; + } + } + + if (prev) { + u64 prev_block_size; + u64 prev_offset; + u64 offset; + + prev_offset = drm_buddy_block_offset(prev); + prev_block_size = drm_buddy_block_size(mm, prev); + offset = drm_buddy_block_offset(root); + + if (offset != (prev_offset + prev_block_size)) { + kunit_err(test, "root offset mismatch\n"); + err = -EINVAL; + } + } + + block = list_first_entry_or_null(&mm->free_list[order], + struct drm_buddy_block, link); + if (block != root) { + kunit_err(test, "root mismatch at order=%u\n", order); + err = -EINVAL; + } + + if (err) + break; + + prev = root; + total += drm_buddy_block_size(mm, root); + } + + if (!err) { + if (total != mm->size) { + kunit_err(test, "expected mm size=%llx, found=%llx\n", + mm->size, total); + err = -EINVAL; + } + return err; + } + + if (prev) { + kunit_err(test, "prev root(%u), dump:\n", i - 1); + igt_dump_block(test, mm, prev); + } + + if (root) { + kunit_err(test, "bad root(%u), dump:\n", i); + igt_dump_block(test, mm, root); + } + + return err; +} + +static void igt_mm_config(u64 *size, u64 *chunk_size) +{ + DRM_RND_STATE(prng, random_seed); + u32 s, ms; + + /* Nothing fancy, just try to get an interesting bit pattern */ + + prandom_seed_state(&prng, random_seed); + + /* Let size be a random number of pages up to 8 GB (2M pages) */ + s = 1 + drm_prandom_u32_max_state((BIT(33 - 12)) - 1, &prng); + /* Let the chunk size be a random power of 2 less than size */ + ms = BIT(drm_prandom_u32_max_state(ilog2(s), &prng)); + /* Round size down to the chunk size */ + s &= -ms; + + /* Convert from pages to bytes */ + *chunk_size = (u64)ms << 12; + *size = (u64)s << 12; +} + +static void igt_buddy_alloc_pathological(struct kunit *test) +{ + u64 mm_size, size, start = 0; + struct drm_buddy_block *block; + const int max_order = 3; + unsigned long flags = 0; + int order, top; + struct drm_buddy mm; + LIST_HEAD(blocks); + LIST_HEAD(holes); + LIST_HEAD(tmp); + + /* + * Create a pot-sized mm, then allocate one of each possible + * order within. This should leave the mm with exactly one + * page left. Free the largest block, then whittle down again. + * Eventually we will have a fully 50% fragmented mm. + */ + + mm_size = PAGE_SIZE << max_order; + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, PAGE_SIZE), + "buddy_init failed\n"); + + KUNIT_EXPECT_EQ(test, mm.max_order, max_order); + + for (top = max_order; top; top--) { + /* Make room by freeing the largest allocated block */ + block = list_first_entry_or_null(&blocks, typeof(*block), link); + if (block) { + list_del(&block->link); + drm_buddy_free_block(&mm, block); + } + + for (order = top; order--;) { + size = get_size(order, PAGE_SIZE); + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, start, + mm_size, size, size, + &tmp, flags), + "buddy_alloc hit -ENOMEM with order=%d, top=%d\n", + order, top); + + block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link); + KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); + + list_move_tail(&block->link, &blocks); + } + + /* There should be one final page for this sub-allocation */ + size = get_size(0, PAGE_SIZE); + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size, + size, size, &tmp, flags), + "buddy_alloc hit -ENOMEM for hole\n"); + + block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link); + KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); + + list_move_tail(&block->link, &holes); + + size = get_size(top, PAGE_SIZE); + KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size, + size, size, &tmp, flags), + "buddy_alloc unexpectedly succeeded at top-order %d/%d, it should be full!", + top, max_order); + } + + drm_buddy_free_list(&mm, &holes); + + /* Nothing larger than blocks of chunk_size now available */ + for (order = 1; order <= max_order; order++) { + size = get_size(order, PAGE_SIZE); + KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size, + size, size, &tmp, flags), + "buddy_alloc unexpectedly succeeded at order %d, it should be full!", + order); + } + + list_splice_tail(&holes, &blocks); + drm_buddy_free_list(&mm, &blocks); + drm_buddy_fini(&mm); +} + +static void igt_buddy_alloc_smoke(struct kunit *test) +{ + u64 mm_size, chunk_size, start = 0; + unsigned long flags = 0; + struct drm_buddy mm; + int *order; + int i; + + DRM_RND_STATE(prng, random_seed); + IGT_TIMEOUT(end_time); + + igt_mm_config(&mm_size, &chunk_size); + + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, chunk_size), + "buddy_init failed\n"); + + order = drm_random_order(mm.max_order + 1, &prng); + KUNIT_ASSERT_TRUE(test, order); + + for (i = 0; i <= mm.max_order; ++i) { + struct drm_buddy_block *block; + int max_order = order[i]; + bool timeout = false; + LIST_HEAD(blocks); + u64 total, size; + LIST_HEAD(tmp); + int order, err; + + KUNIT_ASSERT_FALSE_MSG(test, igt_check_mm(test, &mm), + "pre-mm check failed, abort\n"); + + order = max_order; + total = 0; + + do { +retry: + size = get_size(order, chunk_size); + err = drm_buddy_alloc_blocks(&mm, start, mm_size, size, size, &tmp, flags); + if (err) { + if (err == -ENOMEM) { + KUNIT_FAIL(test, "buddy_alloc hit -ENOMEM with order=%d\n", + order); + } else { + if (order--) { + err = 0; + goto retry; + } + + KUNIT_FAIL(test, "buddy_alloc with order=%d failed\n", + order); + } + + break; + } + + block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link); + KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); + + list_move_tail(&block->link, &blocks); + KUNIT_EXPECT_EQ_MSG(test, drm_buddy_block_order(block), order, + "buddy_alloc order mismatch\n"); + + total += drm_buddy_block_size(&mm, block); + + if (__igt_timeout(end_time, NULL)) { + timeout = true; + break; + } + } while (total < mm.size); + + if (!err) + err = igt_check_blocks(test, &mm, &blocks, total, false); + + drm_buddy_free_list(&mm, &blocks); + + if (!err) { + KUNIT_EXPECT_FALSE_MSG(test, igt_check_mm(test, &mm), + "post-mm check failed\n"); + } + + if (err || timeout) + break; + + cond_resched(); + } + + kfree(order); + drm_buddy_fini(&mm); +} + +static void igt_buddy_alloc_pessimistic(struct kunit *test) +{ + u64 mm_size, size, start = 0; + struct drm_buddy_block *block, *bn; + const unsigned int max_order = 16; + unsigned long flags = 0; + struct drm_buddy mm; + unsigned int order; + LIST_HEAD(blocks); + LIST_HEAD(tmp); + + /* + * Create a pot-sized mm, then allocate one of each possible + * order within. This should leave the mm with exactly one + * page left. + */ + + mm_size = PAGE_SIZE << max_order; + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, PAGE_SIZE), + "buddy_init failed\n"); + + KUNIT_EXPECT_EQ(test, mm.max_order, max_order); + + for (order = 0; order < max_order; order++) { + size = get_size(order, PAGE_SIZE); + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size, + size, size, &tmp, flags), + "buddy_alloc hit -ENOMEM with order=%d\n", + order); + + block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link); + KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); + + list_move_tail(&block->link, &blocks); + } + + /* And now the last remaining block available */ + size = get_size(0, PAGE_SIZE); + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size, + size, size, &tmp, flags), + "buddy_alloc hit -ENOMEM on final alloc\n"); + + block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link); + KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); + + list_move_tail(&block->link, &blocks); + + /* Should be completely full! */ + for (order = max_order; order--;) { + size = get_size(order, PAGE_SIZE); + KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size, + size, size, &tmp, flags), + "buddy_alloc unexpectedly succeeded, it should be full!"); + } + + block = list_last_entry(&blocks, typeof(*block), link); + list_del(&block->link); + drm_buddy_free_block(&mm, block); + + /* As we free in increasing size, we make available larger blocks */ + order = 1; + list_for_each_entry_safe(block, bn, &blocks, link) { + list_del(&block->link); + drm_buddy_free_block(&mm, block); + + size = get_size(order, PAGE_SIZE); + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size, + size, size, &tmp, flags), + "buddy_alloc hit -ENOMEM with order=%d\n", + order); + + block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link); + KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); + + list_del(&block->link); + drm_buddy_free_block(&mm, block); + order++; + } + + /* To confirm, now the whole mm should be available */ + size = get_size(max_order, PAGE_SIZE); + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size, + size, size, &tmp, flags), + "buddy_alloc (realloc) hit -ENOMEM with order=%d\n", + max_order); + + block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link); + KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); + + list_del(&block->link); + drm_buddy_free_block(&mm, block); + drm_buddy_free_list(&mm, &blocks); + drm_buddy_fini(&mm); +} + +static void igt_buddy_alloc_optimistic(struct kunit *test) +{ + u64 mm_size, size, start = 0; + struct drm_buddy_block *block; + unsigned long flags = 0; + const int max_order = 16; + struct drm_buddy mm; + LIST_HEAD(blocks); + LIST_HEAD(tmp); + int order; + + /* + * Create a mm with one block of each order available, and + * try to allocate them all. + */ + + mm_size = PAGE_SIZE * ((1 << (max_order + 1)) - 1); + + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, PAGE_SIZE), + "buddy_init failed\n"); + + KUNIT_EXPECT_EQ(test, mm.max_order, max_order); + + for (order = 0; order <= max_order; order++) { + size = get_size(order, PAGE_SIZE); + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size, + size, size, &tmp, flags), + "buddy_alloc hit -ENOMEM with order=%d\n", + order); + + block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link); + KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); + + list_move_tail(&block->link, &blocks); + } + + /* Should be completely full! */ + size = get_size(0, PAGE_SIZE); + KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size, + size, size, &tmp, flags), + "buddy_alloc unexpectedly succeeded, it should be full!"); + + drm_buddy_free_list(&mm, &blocks); + drm_buddy_fini(&mm); +} + +static void igt_buddy_alloc_range(struct kunit *test) +{ + unsigned long flags = DRM_BUDDY_RANGE_ALLOCATION; + u64 offset, size, rem, chunk_size, end; + unsigned long page_num; + struct drm_buddy mm; + LIST_HEAD(blocks); + + igt_mm_config(&size, &chunk_size); + + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, size, chunk_size), + "buddy_init failed"); + + KUNIT_ASSERT_FALSE_MSG(test, igt_check_mm(test, &mm), + "pre-mm check failed, abort!"); + + rem = mm.size; + offset = 0; + + for_each_prime_number_from(page_num, 1, ULONG_MAX - 1) { + struct drm_buddy_block *block; + LIST_HEAD(tmp); + + size = min(page_num * mm.chunk_size, rem); + end = offset + size; + + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, offset, end, + size, mm.chunk_size, + &tmp, flags), + "alloc_range with offset=%llx, size=%llx failed\n", offset, size); + + block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link); + KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_range has no blocks\n"); + + KUNIT_ASSERT_EQ_MSG(test, drm_buddy_block_offset(block), offset, + "alloc_range start offset mismatch, found=%llx, expected=%llx\n", + drm_buddy_block_offset(block), offset); + + KUNIT_ASSERT_FALSE(test, igt_check_blocks(test, &mm, &tmp, size, true)); + + list_splice_tail(&tmp, &blocks); + + offset += size; + + rem -= size; + if (!rem) + break; + + cond_resched(); + } + + drm_buddy_free_list(&mm, &blocks); + + KUNIT_EXPECT_FALSE_MSG(test, igt_check_mm(test, &mm), "post-mm check failed\n"); + + drm_buddy_fini(&mm); +} + +static void igt_buddy_alloc_limit(struct kunit *test) +{ + u64 size = U64_MAX, start = 0; + struct drm_buddy_block *block; + unsigned long flags = 0; + LIST_HEAD(allocated); + struct drm_buddy mm; + + KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, size, PAGE_SIZE)); + + KUNIT_EXPECT_EQ_MSG(test, mm.max_order, DRM_BUDDY_MAX_ORDER, + "mm.max_order(%d) != %d\n", mm.max_order, + DRM_BUDDY_MAX_ORDER); + + size = mm.chunk_size << mm.max_order; + KUNIT_EXPECT_FALSE(test, drm_buddy_alloc_blocks(&mm, start, size, size, + PAGE_SIZE, &allocated, flags)); + + block = list_first_entry_or_null(&allocated, struct drm_buddy_block, link); + KUNIT_EXPECT_TRUE(test, block); + + KUNIT_EXPECT_EQ_MSG(test, drm_buddy_block_order(block), mm.max_order, + "block order(%d) != %d\n", + drm_buddy_block_order(block), mm.max_order); + + KUNIT_EXPECT_EQ_MSG(test, drm_buddy_block_size(&mm, block), + BIT_ULL(mm.max_order) * PAGE_SIZE, + "block size(%llu) != %llu\n", + drm_buddy_block_size(&mm, block), + BIT_ULL(mm.max_order) * PAGE_SIZE); + + drm_buddy_free_list(&mm, &allocated); + drm_buddy_fini(&mm); +} + +static int drm_buddy_init_test(struct kunit *test) +{ + while (!random_seed) + random_seed = get_random_int(); + + return 0; +} + +static struct kunit_case drm_buddy_tests[] = { + KUNIT_CASE(igt_buddy_alloc_limit), + KUNIT_CASE(igt_buddy_alloc_range), + KUNIT_CASE(igt_buddy_alloc_optimistic), + KUNIT_CASE(igt_buddy_alloc_pessimistic), + KUNIT_CASE(igt_buddy_alloc_smoke), + KUNIT_CASE(igt_buddy_alloc_pathological), + {} +}; + +static struct kunit_suite drm_buddy_test_suite = { + .name = "drm_buddy", + .init = drm_buddy_init_test, + .test_cases = drm_buddy_tests, +}; + +kunit_test_suite(drm_buddy_test_suite); + +MODULE_AUTHOR("Intel Corporation"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/tests/drm_cmdline_parser_test.c b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c new file mode 100644 index 000000000000..59b29cdfdd35 --- /dev/null +++ b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c @@ -0,0 +1,1078 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 Bootlin + * Copyright (c) 2022 MaÃra Canal <mairacanal@riseup.net> + */ + +#include <kunit/test.h> + +#include <drm/drm_connector.h> +#include <drm/drm_modes.h> + +static const struct drm_connector no_connector = {}; + +static void drm_cmdline_test_force_e_only(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "e"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_FALSE(test, mode.specified); + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON); +} + +static void drm_cmdline_test_force_D_only_not_digital(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "D"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_FALSE(test, mode.specified); + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON); +} + +static const struct drm_connector connector_hdmi = { + .connector_type = DRM_MODE_CONNECTOR_HDMIB, +}; + +static void drm_cmdline_test_force_D_only_hdmi(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "D"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &connector_hdmi, &mode)); + KUNIT_EXPECT_FALSE(test, mode.specified); + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON_DIGITAL); +} + +static const struct drm_connector connector_dvi = { + .connector_type = DRM_MODE_CONNECTOR_DVII, +}; + +static void drm_cmdline_test_force_D_only_dvi(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "D"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &connector_dvi, &mode)); + KUNIT_EXPECT_FALSE(test, mode.specified); + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON_DIGITAL); +} + +static void drm_cmdline_test_force_d_only(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "d"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_FALSE(test, mode.specified); + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_OFF); +} + +static void drm_cmdline_test_margin_only(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "m"; + + KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); +} + +static void drm_cmdline_test_interlace_only(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "i"; + + KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); +} + +static void drm_cmdline_test_res(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +static void drm_cmdline_test_res_missing_x(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "x480"; + + KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); +} + +static void drm_cmdline_test_res_missing_y(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "1024x"; + + KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); +} + +static void drm_cmdline_test_res_bad_y(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "1024xtest"; + + KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); +} + +static void drm_cmdline_test_res_missing_y_bpp(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "1024x-24"; + + KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); +} + +static void drm_cmdline_test_res_vesa(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480M"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_TRUE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +static void drm_cmdline_test_res_vesa_rblank(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480MR"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_TRUE(test, mode.rb); + KUNIT_EXPECT_TRUE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +static void drm_cmdline_test_res_rblank(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480R"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_TRUE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +static void drm_cmdline_test_res_bpp(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480-24"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + + KUNIT_EXPECT_TRUE(test, mode.bpp_specified); + KUNIT_EXPECT_EQ(test, mode.bpp, 24); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +static void drm_cmdline_test_res_bad_bpp(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480-test"; + + KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); +} + +static void drm_cmdline_test_res_refresh(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480@60"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + + KUNIT_EXPECT_TRUE(test, mode.refresh_specified); + KUNIT_EXPECT_EQ(test, mode.refresh, 60); + + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +static void drm_cmdline_test_res_bad_refresh(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480@refresh"; + + KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); +} + +static void drm_cmdline_test_res_bpp_refresh(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480-24@60"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + + KUNIT_EXPECT_TRUE(test, mode.refresh_specified); + KUNIT_EXPECT_EQ(test, mode.refresh, 60); + + KUNIT_EXPECT_TRUE(test, mode.bpp_specified); + KUNIT_EXPECT_EQ(test, mode.bpp, 24); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +static void drm_cmdline_test_res_bpp_refresh_interlaced(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480-24@60i"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + + KUNIT_EXPECT_TRUE(test, mode.refresh_specified); + KUNIT_EXPECT_EQ(test, mode.refresh, 60); + + KUNIT_EXPECT_TRUE(test, mode.bpp_specified); + KUNIT_EXPECT_EQ(test, mode.bpp, 24); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_TRUE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +static void drm_cmdline_test_res_bpp_refresh_margins(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480-24@60m"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + + KUNIT_EXPECT_TRUE(test, mode.refresh_specified); + KUNIT_EXPECT_EQ(test, mode.refresh, 60); + + KUNIT_EXPECT_TRUE(test, mode.bpp_specified); + KUNIT_EXPECT_EQ(test, mode.bpp, 24); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_TRUE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +static void drm_cmdline_test_res_bpp_refresh_force_off(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480-24@60d"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + + KUNIT_EXPECT_TRUE(test, mode.refresh_specified); + KUNIT_EXPECT_EQ(test, mode.refresh, 60); + + KUNIT_EXPECT_TRUE(test, mode.bpp_specified); + KUNIT_EXPECT_EQ(test, mode.bpp, 24); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_OFF); +} + +static void drm_cmdline_test_res_bpp_refresh_force_on_off(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480-24@60de"; + + KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); +} + +static void drm_cmdline_test_res_bpp_refresh_force_on(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480-24@60e"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + + KUNIT_EXPECT_TRUE(test, mode.refresh_specified); + KUNIT_EXPECT_EQ(test, mode.refresh, 60); + + KUNIT_EXPECT_TRUE(test, mode.bpp_specified); + KUNIT_EXPECT_EQ(test, mode.bpp, 24); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON); +} + +static void drm_cmdline_test_res_bpp_refresh_force_on_analog(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480-24@60D"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + + KUNIT_EXPECT_TRUE(test, mode.refresh_specified); + KUNIT_EXPECT_EQ(test, mode.refresh, 60); + + KUNIT_EXPECT_TRUE(test, mode.bpp_specified); + KUNIT_EXPECT_EQ(test, mode.bpp, 24); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON); +} + +static void drm_cmdline_test_res_bpp_refresh_force_on_digital(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + static const struct drm_connector connector = { + .connector_type = DRM_MODE_CONNECTOR_DVII, + }; + const char *cmdline = "720x480-24@60D"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + + KUNIT_EXPECT_TRUE(test, mode.refresh_specified); + KUNIT_EXPECT_EQ(test, mode.refresh, 60); + + KUNIT_EXPECT_TRUE(test, mode.bpp_specified); + KUNIT_EXPECT_EQ(test, mode.bpp, 24); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON_DIGITAL); +} + +static void drm_cmdline_test_res_bpp_refresh_interlaced_margins_force_on(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480-24@60ime"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + + KUNIT_EXPECT_TRUE(test, mode.refresh_specified); + KUNIT_EXPECT_EQ(test, mode.refresh, 60); + + KUNIT_EXPECT_TRUE(test, mode.bpp_specified); + KUNIT_EXPECT_EQ(test, mode.bpp, 24); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_TRUE(test, mode.interlace); + KUNIT_EXPECT_TRUE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON); +} + +static void drm_cmdline_test_res_margins_force_on(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480me"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_TRUE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON); +} + +static void drm_cmdline_test_res_vesa_margins(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480Mm"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_TRUE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_TRUE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +static void drm_cmdline_test_res_invalid_mode(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480f"; + + KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); +} + +static void drm_cmdline_test_res_bpp_wrong_place_mode(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480e-24"; + + KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); +} + +static void drm_cmdline_test_name(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "NTSC"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_STREQ(test, mode.name, "NTSC"); + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); +} + +static void drm_cmdline_test_name_bpp(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "NTSC-24"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_STREQ(test, mode.name, "NTSC"); + + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + + KUNIT_EXPECT_TRUE(test, mode.bpp_specified); + KUNIT_EXPECT_EQ(test, mode.bpp, 24); +} + +static void drm_cmdline_test_name_bpp_refresh(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "NTSC-24@60"; + + KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); +} + +static void drm_cmdline_test_name_refresh(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "NTSC@60"; + + KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); +} + +static void drm_cmdline_test_name_refresh_wrong_mode(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "NTSC@60m"; + + KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); +} + +static void drm_cmdline_test_name_refresh_invalid_mode(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "NTSC@60f"; + + KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); +} + +static void drm_cmdline_test_name_option(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "NTSC,rotate=180"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_STREQ(test, mode.name, "NTSC"); + KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_180); +} + +static void drm_cmdline_test_name_bpp_option(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "NTSC-24,rotate=180"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_STREQ(test, mode.name, "NTSC"); + KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_180); + KUNIT_EXPECT_TRUE(test, mode.bpp_specified); + KUNIT_EXPECT_EQ(test, mode.bpp, 24); +} + +static void drm_cmdline_test_rotate_0(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480,rotate=0"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_0); + + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +static void drm_cmdline_test_rotate_90(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480,rotate=90"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_90); + + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +static void drm_cmdline_test_rotate_180(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480,rotate=180"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_180); + + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +static void drm_cmdline_test_rotate_270(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480,rotate=270"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_270); + + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +static void drm_cmdline_test_rotate_multiple(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480,rotate=0,rotate=90"; + + KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); +} + +static void drm_cmdline_test_rotate_invalid_val(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480,rotate=42"; + + KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); +} + +static void drm_cmdline_test_rotate_truncated(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480,rotate="; + + KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); +} + +static void drm_cmdline_test_hmirror(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480,reflect_x"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + KUNIT_EXPECT_EQ(test, mode.rotation_reflection, (DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_X)); + + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +static void drm_cmdline_test_vmirror(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480,reflect_y"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + KUNIT_EXPECT_EQ(test, mode.rotation_reflection, (DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_Y)); + + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +static void drm_cmdline_test_margin_options(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = + "720x480,margin_right=14,margin_left=24,margin_bottom=36,margin_top=42"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + KUNIT_EXPECT_EQ(test, mode.tv_margins.right, 14); + KUNIT_EXPECT_EQ(test, mode.tv_margins.left, 24); + KUNIT_EXPECT_EQ(test, mode.tv_margins.bottom, 36); + KUNIT_EXPECT_EQ(test, mode.tv_margins.top, 42); + + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +static void drm_cmdline_test_multiple_options(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480,rotate=270,reflect_x"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + KUNIT_EXPECT_EQ(test, mode.rotation_reflection, (DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X)); + + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +static void drm_cmdline_test_invalid_option(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480,test=42"; + + KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); +} + +static void drm_cmdline_test_bpp_extra_and_option(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480-24e,rotate=180"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_180); + + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + + KUNIT_EXPECT_TRUE(test, mode.bpp_specified); + KUNIT_EXPECT_EQ(test, mode.bpp, 24); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON); +} + +static void drm_cmdline_test_extra_and_option(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "720x480e,rotate=180"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_TRUE(test, mode.specified); + KUNIT_EXPECT_EQ(test, mode.xres, 720); + KUNIT_EXPECT_EQ(test, mode.yres, 480); + KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_180); + + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON); +} + +static void drm_cmdline_test_freestanding_options(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "margin_right=14,margin_left=24,margin_bottom=36,margin_top=42"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_FALSE(test, mode.specified); + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_EQ(test, mode.tv_margins.right, 14); + KUNIT_EXPECT_EQ(test, mode.tv_margins.left, 24); + KUNIT_EXPECT_EQ(test, mode.tv_margins.bottom, 36); + KUNIT_EXPECT_EQ(test, mode.tv_margins.top, 42); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +static void drm_cmdline_test_freestanding_force_e_and_options(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "e,margin_right=14,margin_left=24,margin_bottom=36,margin_top=42"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_FALSE(test, mode.specified); + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_EQ(test, mode.tv_margins.right, 14); + KUNIT_EXPECT_EQ(test, mode.tv_margins.left, 24); + KUNIT_EXPECT_EQ(test, mode.tv_margins.bottom, 36); + KUNIT_EXPECT_EQ(test, mode.tv_margins.top, 42); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON); +} + +static void drm_cmdline_test_panel_orientation(struct kunit *test) +{ + struct drm_cmdline_mode mode = { }; + const char *cmdline = "panel_orientation=upside_down"; + + KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline, + &no_connector, &mode)); + KUNIT_EXPECT_FALSE(test, mode.specified); + KUNIT_EXPECT_FALSE(test, mode.refresh_specified); + KUNIT_EXPECT_FALSE(test, mode.bpp_specified); + + KUNIT_EXPECT_EQ(test, mode.panel_orientation, DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP); + + KUNIT_EXPECT_FALSE(test, mode.rb); + KUNIT_EXPECT_FALSE(test, mode.cvt); + KUNIT_EXPECT_FALSE(test, mode.interlace); + KUNIT_EXPECT_FALSE(test, mode.margins); + KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED); +} + +static struct kunit_case drm_cmdline_parser_tests[] = { + KUNIT_CASE(drm_cmdline_test_force_d_only), + KUNIT_CASE(drm_cmdline_test_force_D_only_dvi), + KUNIT_CASE(drm_cmdline_test_force_D_only_hdmi), + KUNIT_CASE(drm_cmdline_test_force_D_only_not_digital), + KUNIT_CASE(drm_cmdline_test_force_e_only), + KUNIT_CASE(drm_cmdline_test_margin_only), + KUNIT_CASE(drm_cmdline_test_interlace_only), + KUNIT_CASE(drm_cmdline_test_res), + KUNIT_CASE(drm_cmdline_test_res_missing_x), + KUNIT_CASE(drm_cmdline_test_res_missing_y), + KUNIT_CASE(drm_cmdline_test_res_bad_y), + KUNIT_CASE(drm_cmdline_test_res_missing_y_bpp), + KUNIT_CASE(drm_cmdline_test_res_vesa), + KUNIT_CASE(drm_cmdline_test_res_vesa_rblank), + KUNIT_CASE(drm_cmdline_test_res_rblank), + KUNIT_CASE(drm_cmdline_test_res_bpp), + KUNIT_CASE(drm_cmdline_test_res_bad_bpp), + KUNIT_CASE(drm_cmdline_test_res_refresh), + KUNIT_CASE(drm_cmdline_test_res_bad_refresh), + KUNIT_CASE(drm_cmdline_test_res_bpp_refresh), + KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_interlaced), + KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_margins), + KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_force_off), + KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_force_on_off), + KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_force_on), + KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_force_on_analog), + KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_force_on_digital), + KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_interlaced_margins_force_on), + KUNIT_CASE(drm_cmdline_test_res_margins_force_on), + KUNIT_CASE(drm_cmdline_test_res_vesa_margins), + KUNIT_CASE(drm_cmdline_test_res_invalid_mode), + KUNIT_CASE(drm_cmdline_test_res_bpp_wrong_place_mode), + KUNIT_CASE(drm_cmdline_test_name), + KUNIT_CASE(drm_cmdline_test_name_bpp), + KUNIT_CASE(drm_cmdline_test_name_refresh), + KUNIT_CASE(drm_cmdline_test_name_bpp_refresh), + KUNIT_CASE(drm_cmdline_test_name_refresh_wrong_mode), + KUNIT_CASE(drm_cmdline_test_name_refresh_invalid_mode), + KUNIT_CASE(drm_cmdline_test_name_option), + KUNIT_CASE(drm_cmdline_test_name_bpp_option), + KUNIT_CASE(drm_cmdline_test_rotate_0), + KUNIT_CASE(drm_cmdline_test_rotate_90), + KUNIT_CASE(drm_cmdline_test_rotate_180), + KUNIT_CASE(drm_cmdline_test_rotate_270), + KUNIT_CASE(drm_cmdline_test_rotate_multiple), + KUNIT_CASE(drm_cmdline_test_rotate_invalid_val), + KUNIT_CASE(drm_cmdline_test_rotate_truncated), + KUNIT_CASE(drm_cmdline_test_hmirror), + KUNIT_CASE(drm_cmdline_test_vmirror), + KUNIT_CASE(drm_cmdline_test_margin_options), + KUNIT_CASE(drm_cmdline_test_multiple_options), + KUNIT_CASE(drm_cmdline_test_invalid_option), + KUNIT_CASE(drm_cmdline_test_bpp_extra_and_option), + KUNIT_CASE(drm_cmdline_test_extra_and_option), + KUNIT_CASE(drm_cmdline_test_freestanding_options), + KUNIT_CASE(drm_cmdline_test_freestanding_force_e_and_options), + KUNIT_CASE(drm_cmdline_test_panel_orientation), + {} +}; + +static struct kunit_suite drm_cmdline_parser_test_suite = { + .name = "drm_cmdline_parser", + .test_cases = drm_cmdline_parser_tests +}; + +kunit_test_suite(drm_cmdline_parser_test_suite); + +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/tests/drm_damage_helper_test.c b/drivers/gpu/drm/tests/drm_damage_helper_test.c new file mode 100644 index 000000000000..bf250bd08d7e --- /dev/null +++ b/drivers/gpu/drm/tests/drm_damage_helper_test.c @@ -0,0 +1,634 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Test case for drm_damage_helper functions + * + * Copyright (c) 2022 MaÃra Canal <mairacanal@riseup.net> + */ + +#include <kunit/test.h> + +#include <drm/drm_damage_helper.h> +#include <drm/drm_framebuffer.h> +#include <drm/drm_plane.h> +#include <drm/drm_drv.h> + +struct drm_damage_mock { + struct drm_driver driver; + struct drm_device device; + struct drm_object_properties obj_props; + struct drm_plane plane; + struct drm_property prop; + struct drm_framebuffer fb; + struct drm_plane_state state; + struct drm_plane_state old_state; +}; + +static int drm_damage_helper_init(struct kunit *test) +{ + struct drm_damage_mock *mock; + + mock = kunit_kzalloc(test, sizeof(*mock), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mock); + + mock->fb.width = 2048; + mock->fb.height = 2048; + + mock->state.crtc = ZERO_SIZE_PTR; + mock->state.fb = &mock->fb; + mock->state.visible = true; + + mock->old_state.plane = &mock->plane; + mock->state.plane = &mock->plane; + + /* just enough so that drm_plane_enable_fb_damage_clips() works */ + mock->device.driver = &mock->driver; + mock->device.mode_config.prop_fb_damage_clips = &mock->prop; + mock->plane.dev = &mock->device; + mock->obj_props.count = 0; + mock->plane.base.properties = &mock->obj_props; + mock->prop.base.id = 1; /* 0 is an invalid id */ + mock->prop.dev = &mock->device; + + drm_plane_enable_fb_damage_clips(&mock->plane); + + test->priv = mock; + + return 0; +} + +static void set_plane_src(struct drm_plane_state *state, int x1, int y1, int x2, + int y2) +{ + state->src.x1 = x1; + state->src.y1 = y1; + state->src.x2 = x2; + state->src.y2 = y2; +} + +static void set_damage_clip(struct drm_mode_rect *r, int x1, int y1, int x2, + int y2) +{ + r->x1 = x1; + r->y1 = y1; + r->x2 = x2; + r->y2 = y2; +} + +static void set_damage_blob(struct drm_property_blob *damage_blob, + struct drm_mode_rect *r, u32 size) +{ + damage_blob->length = size; + damage_blob->data = r; +} + +static void set_plane_damage(struct drm_plane_state *state, + struct drm_property_blob *damage_blob) +{ + state->fb_damage_clips = damage_blob; +} + +static void check_damage_clip(struct kunit *test, struct drm_rect *r, + int x1, int y1, int x2, int y2) +{ + struct drm_damage_mock *mock = test->priv; + struct drm_plane_state state = mock->state; + + /* + * Round down x1/y1 and round up x2/y2. This is because damage is not in + * 16.16 fixed point so to catch all pixels. + */ + int src_x1 = state.src.x1 >> 16; + int src_y1 = state.src.y1 >> 16; + int src_x2 = (state.src.x2 >> 16) + !!(state.src.x2 & 0xFFFF); + int src_y2 = (state.src.y2 >> 16) + !!(state.src.y2 & 0xFFFF); + + if (x1 >= x2 || y1 >= y2) + KUNIT_FAIL(test, "Cannot have damage clip with no dimension."); + if (x1 < src_x1 || y1 < src_y1 || x2 > src_x2 || y2 > src_y2) + KUNIT_FAIL(test, "Damage cannot be outside rounded plane src."); + if (r->x1 != x1 || r->y1 != y1 || r->x2 != x2 || r->y2 != y2) + KUNIT_FAIL(test, "Damage = %d %d %d %d, want = %d %d %d %d", + r->x1, r->y1, r->x2, r->y2, x1, y1, x2, y2); +} + +static void igt_damage_iter_no_damage(struct kunit *test) +{ + struct drm_damage_mock *mock = test->priv; + struct drm_atomic_helper_damage_iter iter; + struct drm_rect clip; + u32 num_hits = 0; + + /* Plane src same as fb size. */ + set_plane_src(&mock->old_state, 0, 0, mock->fb.width << 16, mock->fb.height << 16); + set_plane_src(&mock->state, 0, 0, mock->fb.width << 16, mock->fb.height << 16); + drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state); + drm_atomic_for_each_plane_damage(&iter, &clip) + num_hits++; + + KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return plane src as damage."); + check_damage_clip(test, &clip, 0, 0, 2048, 2048); +} + +static void igt_damage_iter_no_damage_fractional_src(struct kunit *test) +{ + struct drm_damage_mock *mock = test->priv; + struct drm_atomic_helper_damage_iter iter; + struct drm_rect clip; + u32 num_hits = 0; + + /* Plane src has fractional part. */ + set_plane_src(&mock->old_state, 0x3fffe, 0x3fffe, + 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16)); + set_plane_src(&mock->state, 0x3fffe, 0x3fffe, + 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16)); + drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state); + drm_atomic_for_each_plane_damage(&iter, &clip) + num_hits++; + + KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, + "Should return rounded off plane src as damage."); + check_damage_clip(test, &clip, 3, 3, 1028, 772); +} + +static void igt_damage_iter_no_damage_src_moved(struct kunit *test) +{ + struct drm_damage_mock *mock = test->priv; + struct drm_atomic_helper_damage_iter iter; + struct drm_rect clip; + u32 num_hits = 0; + + /* Plane src moved since old plane state. */ + set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16); + set_plane_src(&mock->state, 10 << 16, 10 << 16, + (10 + 1024) << 16, (10 + 768) << 16); + drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state); + drm_atomic_for_each_plane_damage(&iter, &clip) + num_hits++; + + KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return plane src as damage."); + check_damage_clip(test, &clip, 10, 10, 1034, 778); +} + +static void igt_damage_iter_no_damage_fractional_src_moved(struct kunit *test) +{ + struct drm_damage_mock *mock = test->priv; + struct drm_atomic_helper_damage_iter iter; + struct drm_rect clip; + u32 num_hits = 0; + + /* Plane src has fractional part and it moved since old plane state. */ + set_plane_src(&mock->old_state, 0x3fffe, 0x3fffe, + 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16)); + set_plane_src(&mock->state, 0x40002, 0x40002, + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); + drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state); + drm_atomic_for_each_plane_damage(&iter, &clip) + num_hits++; + + KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return plane src as damage."); + check_damage_clip(test, &clip, 4, 4, 1029, 773); +} + +static void igt_damage_iter_no_damage_not_visible(struct kunit *test) +{ + struct drm_damage_mock *mock = test->priv; + struct drm_atomic_helper_damage_iter iter; + struct drm_rect clip; + u32 num_hits = 0; + + mock->state.visible = false; + + set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16); + set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16); + drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state); + drm_atomic_for_each_plane_damage(&iter, &clip) + num_hits++; + + KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should have no damage."); +} + +static void igt_damage_iter_no_damage_no_crtc(struct kunit *test) +{ + struct drm_damage_mock *mock = test->priv; + struct drm_atomic_helper_damage_iter iter; + struct drm_rect clip; + u32 num_hits = 0; + + mock->state.crtc = NULL; + + set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16); + set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16); + drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state); + drm_atomic_for_each_plane_damage(&iter, &clip) + num_hits++; + + KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should have no damage."); +} + +static void igt_damage_iter_no_damage_no_fb(struct kunit *test) +{ + struct drm_damage_mock *mock = test->priv; + struct drm_atomic_helper_damage_iter iter; + struct drm_rect clip; + u32 num_hits = 0; + + mock->state.fb = NULL; + + set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16); + set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16); + drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state); + drm_atomic_for_each_plane_damage(&iter, &clip) + num_hits++; + + KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should have no damage."); +} + +static void igt_damage_iter_simple_damage(struct kunit *test) +{ + struct drm_damage_mock *mock = test->priv; + struct drm_atomic_helper_damage_iter iter; + struct drm_property_blob damage_blob; + struct drm_mode_rect damage; + struct drm_rect clip; + u32 num_hits = 0; + + set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16); + set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16); + /* Damage set to plane src */ + set_damage_clip(&damage, 0, 0, 1024, 768); + set_damage_blob(&damage_blob, &damage, sizeof(damage)); + set_plane_damage(&mock->state, &damage_blob); + drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state); + drm_atomic_for_each_plane_damage(&iter, &clip) + num_hits++; + + KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return damage when set."); + check_damage_clip(test, &clip, 0, 0, 1024, 768); +} + +static void igt_damage_iter_single_damage(struct kunit *test) +{ + struct drm_damage_mock *mock = test->priv; + struct drm_atomic_helper_damage_iter iter; + struct drm_property_blob damage_blob; + struct drm_mode_rect damage; + struct drm_rect clip; + u32 num_hits = 0; + + set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16); + set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16); + set_damage_clip(&damage, 256, 192, 768, 576); + set_damage_blob(&damage_blob, &damage, sizeof(damage)); + set_plane_damage(&mock->state, &damage_blob); + drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state); + drm_atomic_for_each_plane_damage(&iter, &clip) + num_hits++; + + KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return damage when set."); + check_damage_clip(test, &clip, 256, 192, 768, 576); +} + +static void igt_damage_iter_single_damage_intersect_src(struct kunit *test) +{ + struct drm_damage_mock *mock = test->priv; + struct drm_atomic_helper_damage_iter iter; + struct drm_property_blob damage_blob; + struct drm_mode_rect damage; + struct drm_rect clip; + u32 num_hits = 0; + + set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16); + set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16); + /* Damage intersect with plane src. */ + set_damage_clip(&damage, 256, 192, 1360, 768); + set_damage_blob(&damage_blob, &damage, sizeof(damage)); + set_plane_damage(&mock->state, &damage_blob); + drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state); + drm_atomic_for_each_plane_damage(&iter, &clip) + num_hits++; + + KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return damage clipped to src."); + check_damage_clip(test, &clip, 256, 192, 1024, 768); +} + +static void igt_damage_iter_single_damage_outside_src(struct kunit *test) +{ + struct drm_damage_mock *mock = test->priv; + struct drm_atomic_helper_damage_iter iter; + struct drm_property_blob damage_blob; + struct drm_mode_rect damage; + struct drm_rect clip; + u32 num_hits = 0; + + set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16); + set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16); + /* Damage clip outside plane src */ + set_damage_clip(&damage, 1360, 1360, 1380, 1380); + set_damage_blob(&damage_blob, &damage, sizeof(damage)); + set_plane_damage(&mock->state, &damage_blob); + drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state); + drm_atomic_for_each_plane_damage(&iter, &clip) + num_hits++; + + KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should have no damage."); +} + +static void igt_damage_iter_single_damage_fractional_src(struct kunit *test) +{ + struct drm_damage_mock *mock = test->priv; + struct drm_atomic_helper_damage_iter iter; + struct drm_property_blob damage_blob; + struct drm_mode_rect damage; + struct drm_rect clip; + u32 num_hits = 0; + + /* Plane src has fractional part. */ + set_plane_src(&mock->old_state, 0x40002, 0x40002, + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); + set_plane_src(&mock->state, 0x40002, 0x40002, + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); + set_damage_clip(&damage, 10, 10, 256, 330); + set_damage_blob(&damage_blob, &damage, sizeof(damage)); + set_plane_damage(&mock->state, &damage_blob); + drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state); + drm_atomic_for_each_plane_damage(&iter, &clip) + num_hits++; + + KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return damage when set."); + check_damage_clip(test, &clip, 10, 10, 256, 330); +} + +static void igt_damage_iter_single_damage_intersect_fractional_src(struct kunit *test) +{ + struct drm_damage_mock *mock = test->priv; + struct drm_atomic_helper_damage_iter iter; + struct drm_property_blob damage_blob; + struct drm_mode_rect damage; + struct drm_rect clip; + u32 num_hits = 0; + + /* Plane src has fractional part. */ + set_plane_src(&mock->old_state, 0x40002, 0x40002, + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); + set_plane_src(&mock->state, 0x40002, 0x40002, + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); + /* Damage intersect with plane src. */ + set_damage_clip(&damage, 10, 1, 1360, 330); + set_damage_blob(&damage_blob, &damage, sizeof(damage)); + set_plane_damage(&mock->state, &damage_blob); + drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state); + drm_atomic_for_each_plane_damage(&iter, &clip) + num_hits++; + + KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, + "Should return damage clipped to rounded off src."); + check_damage_clip(test, &clip, 10, 4, 1029, 330); +} + +static void igt_damage_iter_single_damage_outside_fractional_src(struct kunit *test) +{ + struct drm_damage_mock *mock = test->priv; + struct drm_atomic_helper_damage_iter iter; + struct drm_property_blob damage_blob; + struct drm_mode_rect damage; + struct drm_rect clip; + u32 num_hits = 0; + + /* Plane src has fractional part. */ + set_plane_src(&mock->old_state, 0x40002, 0x40002, + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); + set_plane_src(&mock->state, 0x40002, 0x40002, + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); + /* Damage clip outside plane src */ + set_damage_clip(&damage, 1360, 1360, 1380, 1380); + set_damage_blob(&damage_blob, &damage, sizeof(damage)); + set_plane_damage(&mock->state, &damage_blob); + drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state); + drm_atomic_for_each_plane_damage(&iter, &clip) + num_hits++; + + KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should have no damage."); +} + +static void igt_damage_iter_single_damage_src_moved(struct kunit *test) +{ + struct drm_damage_mock *mock = test->priv; + struct drm_atomic_helper_damage_iter iter; + struct drm_property_blob damage_blob; + struct drm_mode_rect damage; + struct drm_rect clip; + u32 num_hits = 0; + + /* Plane src moved since old plane state. */ + set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16); + set_plane_src(&mock->state, 10 << 16, 10 << 16, + (10 + 1024) << 16, (10 + 768) << 16); + set_damage_clip(&damage, 20, 30, 256, 256); + set_damage_blob(&damage_blob, &damage, sizeof(damage)); + set_plane_damage(&mock->state, &damage_blob); + drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state); + drm_atomic_for_each_plane_damage(&iter, &clip) + num_hits++; + + KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, + "Should return plane src as damage."); + check_damage_clip(test, &clip, 10, 10, 1034, 778); +} + +static void igt_damage_iter_single_damage_fractional_src_moved(struct kunit *test) +{ + struct drm_damage_mock *mock = test->priv; + struct drm_atomic_helper_damage_iter iter; + struct drm_property_blob damage_blob; + struct drm_mode_rect damage; + struct drm_rect clip; + u32 num_hits = 0; + + /* Plane src with fractional part moved since old plane state. */ + set_plane_src(&mock->old_state, 0x3fffe, 0x3fffe, + 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16)); + set_plane_src(&mock->state, 0x40002, 0x40002, + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); + /* Damage intersect with plane src. */ + set_damage_clip(&damage, 20, 30, 1360, 256); + set_damage_blob(&damage_blob, &damage, sizeof(damage)); + set_plane_damage(&mock->state, &damage_blob); + drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state); + drm_atomic_for_each_plane_damage(&iter, &clip) + num_hits++; + + KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, + "Should return rounded off plane as damage."); + check_damage_clip(test, &clip, 4, 4, 1029, 773); +} + +static void igt_damage_iter_damage(struct kunit *test) +{ + struct drm_damage_mock *mock = test->priv; + struct drm_atomic_helper_damage_iter iter; + struct drm_property_blob damage_blob; + struct drm_mode_rect damage[2]; + struct drm_rect clip; + u32 num_hits = 0; + + set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16); + set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16); + /* 2 damage clips. */ + set_damage_clip(&damage[0], 20, 30, 200, 180); + set_damage_clip(&damage[1], 240, 200, 280, 250); + set_damage_blob(&damage_blob, &damage[0], sizeof(damage)); + set_plane_damage(&mock->state, &damage_blob); + drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state); + drm_atomic_for_each_plane_damage(&iter, &clip) { + if (num_hits == 0) + check_damage_clip(test, &clip, 20, 30, 200, 180); + if (num_hits == 1) + check_damage_clip(test, &clip, 240, 200, 280, 250); + num_hits++; + } + + KUNIT_EXPECT_EQ_MSG(test, num_hits, 2, "Should return damage when set."); +} + +static void igt_damage_iter_damage_one_intersect(struct kunit *test) +{ + struct drm_damage_mock *mock = test->priv; + struct drm_atomic_helper_damage_iter iter; + struct drm_property_blob damage_blob; + struct drm_mode_rect damage[2]; + struct drm_rect clip; + u32 num_hits = 0; + + set_plane_src(&mock->old_state, 0x40002, 0x40002, + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); + set_plane_src(&mock->state, 0x40002, 0x40002, + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); + /* 2 damage clips, one intersect plane src. */ + set_damage_clip(&damage[0], 20, 30, 200, 180); + set_damage_clip(&damage[1], 2, 2, 1360, 1360); + set_damage_blob(&damage_blob, &damage[0], sizeof(damage)); + set_plane_damage(&mock->state, &damage_blob); + drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state); + drm_atomic_for_each_plane_damage(&iter, &clip) { + if (num_hits == 0) + check_damage_clip(test, &clip, 20, 30, 200, 180); + if (num_hits == 1) + check_damage_clip(test, &clip, 4, 4, 1029, 773); + num_hits++; + } + + KUNIT_EXPECT_EQ_MSG(test, num_hits, 2, "Should return damage when set."); +} + +static void igt_damage_iter_damage_one_outside(struct kunit *test) +{ + struct drm_damage_mock *mock = test->priv; + struct drm_atomic_helper_damage_iter iter; + struct drm_property_blob damage_blob; + struct drm_mode_rect damage[2]; + struct drm_rect clip; + u32 num_hits = 0; + + set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16); + set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16); + /* 2 damage clips, one outside plane src. */ + set_damage_clip(&damage[0], 1360, 1360, 1380, 1380); + set_damage_clip(&damage[1], 240, 200, 280, 250); + set_damage_blob(&damage_blob, &damage[0], sizeof(damage)); + set_plane_damage(&mock->state, &damage_blob); + drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state); + drm_atomic_for_each_plane_damage(&iter, &clip) + num_hits++; + + KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return damage when set."); + check_damage_clip(test, &clip, 240, 200, 280, 250); +} + +static void igt_damage_iter_damage_src_moved(struct kunit *test) +{ + struct drm_damage_mock *mock = test->priv; + struct drm_atomic_helper_damage_iter iter; + struct drm_property_blob damage_blob; + struct drm_mode_rect damage[2]; + struct drm_rect clip; + u32 num_hits = 0; + + set_plane_src(&mock->old_state, 0x40002, 0x40002, + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); + set_plane_src(&mock->state, 0x3fffe, 0x3fffe, + 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16)); + /* 2 damage clips, one outside plane src. */ + set_damage_clip(&damage[0], 1360, 1360, 1380, 1380); + set_damage_clip(&damage[1], 240, 200, 280, 250); + set_damage_blob(&damage_blob, &damage[0], sizeof(damage)); + set_plane_damage(&mock->state, &damage_blob); + drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state); + drm_atomic_for_each_plane_damage(&iter, &clip) + num_hits++; + + KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, + "Should return round off plane src as damage."); + check_damage_clip(test, &clip, 3, 3, 1028, 772); +} + +static void igt_damage_iter_damage_not_visible(struct kunit *test) +{ + struct drm_damage_mock *mock = test->priv; + struct drm_atomic_helper_damage_iter iter; + struct drm_property_blob damage_blob; + struct drm_mode_rect damage[2]; + struct drm_rect clip; + u32 num_hits = 0; + + mock->state.visible = false; + + set_plane_src(&mock->old_state, 0x40002, 0x40002, + 0x40002 + (1024 << 16), 0x40002 + (768 << 16)); + set_plane_src(&mock->state, 0x3fffe, 0x3fffe, + 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16)); + /* 2 damage clips, one outside plane src. */ + set_damage_clip(&damage[0], 1360, 1360, 1380, 1380); + set_damage_clip(&damage[1], 240, 200, 280, 250); + set_damage_blob(&damage_blob, &damage[0], sizeof(damage)); + set_plane_damage(&mock->state, &damage_blob); + drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state); + drm_atomic_for_each_plane_damage(&iter, &clip) + num_hits++; + + KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should not return any damage."); +} + +static struct kunit_case drm_damage_helper_tests[] = { + KUNIT_CASE(igt_damage_iter_no_damage), + KUNIT_CASE(igt_damage_iter_no_damage_fractional_src), + KUNIT_CASE(igt_damage_iter_no_damage_src_moved), + KUNIT_CASE(igt_damage_iter_no_damage_fractional_src_moved), + KUNIT_CASE(igt_damage_iter_no_damage_not_visible), + KUNIT_CASE(igt_damage_iter_no_damage_no_crtc), + KUNIT_CASE(igt_damage_iter_no_damage_no_fb), + KUNIT_CASE(igt_damage_iter_simple_damage), + KUNIT_CASE(igt_damage_iter_single_damage), + KUNIT_CASE(igt_damage_iter_single_damage_intersect_src), + KUNIT_CASE(igt_damage_iter_single_damage_outside_src), + KUNIT_CASE(igt_damage_iter_single_damage_fractional_src), + KUNIT_CASE(igt_damage_iter_single_damage_intersect_fractional_src), + KUNIT_CASE(igt_damage_iter_single_damage_outside_fractional_src), + KUNIT_CASE(igt_damage_iter_single_damage_src_moved), + KUNIT_CASE(igt_damage_iter_single_damage_fractional_src_moved), + KUNIT_CASE(igt_damage_iter_damage), + KUNIT_CASE(igt_damage_iter_damage_one_intersect), + KUNIT_CASE(igt_damage_iter_damage_one_outside), + KUNIT_CASE(igt_damage_iter_damage_src_moved), + KUNIT_CASE(igt_damage_iter_damage_not_visible), + { } +}; + +static struct kunit_suite drm_damage_helper_test_suite = { + .name = "drm_damage_helper", + .init = drm_damage_helper_init, + .test_cases = drm_damage_helper_tests, +}; + +kunit_test_suite(drm_damage_helper_test_suite); + +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c b/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c index 4caa9be900ac..1d2fade56227 100644 --- a/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c +++ b/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c @@ -1,19 +1,22 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Test cases for the DRM DP MST helpers + * + * Copyright (c) 2022 MaÃra Canal <mairacanal@riseup.net> */ #define PREFIX_STR "[drm_dp_mst_helper]" +#include <kunit/test.h> + #include <linux/random.h> #include <drm/display/drm_dp_mst_helper.h> #include <drm/drm_print.h> #include "../display/drm_dp_mst_topology_internal.h" -#include "test-drm_modeset_common.h" -int igt_dp_mst_calc_pbn_mode(void *ignored) +static void igt_dp_mst_calc_pbn_mode(struct kunit *test) { int pbn, i; const struct { @@ -33,13 +36,11 @@ int igt_dp_mst_calc_pbn_mode(void *ignored) pbn = drm_dp_calc_pbn_mode(test_params[i].rate, test_params[i].bpp, test_params[i].dsc); - FAIL(pbn != test_params[i].expected, - "Expected PBN %d for clock %d bpp %d, got %d\n", + KUNIT_EXPECT_EQ_MSG(test, pbn, test_params[i].expected, + "Expected PBN %d for clock %d bpp %d, got %d\n", test_params[i].expected, test_params[i].rate, test_params[i].bpp, pbn); } - - return 0; } static bool @@ -176,66 +177,64 @@ out: return result; } -int igt_dp_mst_sideband_msg_req_decode(void *unused) +static void igt_dp_mst_sideband_msg_req_decode(struct kunit *test) { struct drm_dp_sideband_msg_req_body in = { 0 }; u8 data[] = { 0xff, 0x0, 0xdd }; int i; -#define DO_TEST() FAIL_ON(!sideband_msg_req_encode_decode(&in)) - in.req_type = DP_ENUM_PATH_RESOURCES; in.u.port_num.port_number = 5; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.req_type = DP_POWER_UP_PHY; in.u.port_num.port_number = 5; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.req_type = DP_POWER_DOWN_PHY; in.u.port_num.port_number = 5; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.req_type = DP_ALLOCATE_PAYLOAD; in.u.allocate_payload.number_sdp_streams = 3; for (i = 0; i < in.u.allocate_payload.number_sdp_streams; i++) in.u.allocate_payload.sdp_stream_sink[i] = i + 1; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.u.allocate_payload.port_number = 0xf; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.u.allocate_payload.vcpi = 0x7f; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.u.allocate_payload.pbn = U16_MAX; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.req_type = DP_QUERY_PAYLOAD; in.u.query_payload.port_number = 0xf; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.u.query_payload.vcpi = 0x7f; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.req_type = DP_REMOTE_DPCD_READ; in.u.dpcd_read.port_number = 0xf; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.u.dpcd_read.dpcd_address = 0xfedcb; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.u.dpcd_read.num_bytes = U8_MAX; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.req_type = DP_REMOTE_DPCD_WRITE; in.u.dpcd_write.port_number = 0xf; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.u.dpcd_write.dpcd_address = 0xfedcb; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.u.dpcd_write.num_bytes = ARRAY_SIZE(data); in.u.dpcd_write.bytes = data; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.req_type = DP_REMOTE_I2C_READ; in.u.i2c_read.port_number = 0xf; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.u.i2c_read.read_i2c_device_id = 0x7f; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.u.i2c_read.num_transactions = 3; in.u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3; for (i = 0; i < in.u.i2c_read.num_transactions; i++) { @@ -244,32 +243,44 @@ int igt_dp_mst_sideband_msg_req_decode(void *unused) in.u.i2c_read.transactions[i].i2c_dev_id = 0x7f & ~i; in.u.i2c_read.transactions[i].i2c_transaction_delay = 0xf & ~i; } - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.req_type = DP_REMOTE_I2C_WRITE; in.u.i2c_write.port_number = 0xf; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.u.i2c_write.write_i2c_device_id = 0x7f; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.u.i2c_write.num_bytes = ARRAY_SIZE(data); in.u.i2c_write.bytes = data; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.req_type = DP_QUERY_STREAM_ENC_STATUS; in.u.enc_status.stream_id = 1; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); get_random_bytes(in.u.enc_status.client_id, sizeof(in.u.enc_status.client_id)); - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.u.enc_status.stream_event = 3; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.u.enc_status.valid_stream_event = 0; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.u.enc_status.stream_behavior = 3; - DO_TEST(); + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); in.u.enc_status.valid_stream_behavior = 1; - DO_TEST(); - -#undef DO_TEST - return 0; + KUNIT_EXPECT_TRUE(test, sideband_msg_req_encode_decode(&in)); } + +static struct kunit_case drm_dp_mst_helper_tests[] = { + KUNIT_CASE(igt_dp_mst_calc_pbn_mode), + KUNIT_CASE(igt_dp_mst_sideband_msg_req_decode), + { } +}; + +static struct kunit_suite drm_dp_mst_helper_test_suite = { + .name = "drm_dp_mst_helper", + .test_cases = drm_dp_mst_helper_tests, +}; + +kunit_test_suite(drm_dp_mst_helper_test_suite); + +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/tests/drm_format_helper_test.c b/drivers/gpu/drm/tests/drm_format_helper_test.c index 98583bf56044..828487071796 100644 --- a/drivers/gpu/drm/tests/drm_format_helper_test.c +++ b/drivers/gpu/drm/tests/drm_format_helper_test.c @@ -16,34 +16,59 @@ #define TEST_BUF_SIZE 50 -struct xrgb8888_to_rgb332_case { +struct convert_to_rgb332_result { + unsigned int dst_pitch; + const u8 expected[TEST_BUF_SIZE]; +}; + +struct convert_to_rgb565_result { + unsigned int dst_pitch; + const u16 expected[TEST_BUF_SIZE]; + const u16 expected_swab[TEST_BUF_SIZE]; +}; + +struct convert_xrgb8888_case { const char *name; unsigned int pitch; - unsigned int dst_pitch; struct drm_rect clip; const u32 xrgb8888[TEST_BUF_SIZE]; - const u8 expected[4 * TEST_BUF_SIZE]; + struct convert_to_rgb332_result rgb332_result; + struct convert_to_rgb565_result rgb565_result; }; -static struct xrgb8888_to_rgb332_case xrgb8888_to_rgb332_cases[] = { +static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { { .name = "single_pixel_source_buffer", .pitch = 1 * 4, - .dst_pitch = 0, .clip = DRM_RECT_INIT(0, 0, 1, 1), .xrgb8888 = { 0x01FF0000 }, - .expected = { 0xE0 }, + .rgb332_result = { + .dst_pitch = 0, + .expected = { 0xE0 }, + }, + .rgb565_result = { + .dst_pitch = 0, + .expected = { 0xF800 }, + .expected_swab = { 0x00F8 }, + }, }, { .name = "single_pixel_clip_rectangle", .pitch = 2 * 4, - .dst_pitch = 0, .clip = DRM_RECT_INIT(1, 1, 1, 1), .xrgb8888 = { 0x00000000, 0x00000000, 0x00000000, 0x10FF0000, }, - .expected = { 0xE0 }, + .rgb332_result = { + .dst_pitch = 0, + .expected = { 0xE0 }, + }, + .rgb565_result = { + .dst_pitch = 0, + .expected = { 0xF800 }, + .expected_swab = { 0x00F8 }, + }, }, { /* Well known colors: White, black, red, green, blue, magenta, @@ -52,7 +77,6 @@ static struct xrgb8888_to_rgb332_case xrgb8888_to_rgb332_cases[] = { */ .name = "well_known_colors", .pitch = 4 * 4, - .dst_pitch = 0, .clip = DRM_RECT_INIT(1, 1, 2, 4), .xrgb8888 = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, @@ -61,28 +85,61 @@ static struct xrgb8888_to_rgb332_case xrgb8888_to_rgb332_cases[] = { 0x00000000, 0x550000FF, 0x66FF00FF, 0x00000000, 0x00000000, 0x77FFFF00, 0x8800FFFF, 0x00000000, }, - .expected = { - 0xFF, 0x00, - 0xE0, 0x1C, - 0x03, 0xE3, - 0xFC, 0x1F, + .rgb332_result = { + .dst_pitch = 0, + .expected = { + 0xFF, 0x00, + 0xE0, 0x1C, + 0x03, 0xE3, + 0xFC, 0x1F, + }, + }, + .rgb565_result = { + .dst_pitch = 0, + .expected = { + 0xFFFF, 0x0000, + 0xF800, 0x07E0, + 0x001F, 0xF81F, + 0xFFE0, 0x07FF, + }, + .expected_swab = { + 0xFFFF, 0x0000, + 0x00F8, 0xE007, + 0x1F00, 0x1FF8, + 0xE0FF, 0xFF07, + }, }, }, { /* Randomly picked colors. Full buffer within the clip area. */ .name = "destination_pitch", .pitch = 3 * 4, - .dst_pitch = 5, .clip = DRM_RECT_INIT(0, 0, 3, 3), .xrgb8888 = { 0xA10E449C, 0xB1114D05, 0xC1A80303, 0xD16C7073, 0xA20E449C, 0xB2114D05, 0xC2A80303, 0xD26C7073, 0xA30E449C, }, - .expected = { - 0x0A, 0x08, 0xA0, 0x00, 0x00, - 0x6D, 0x0A, 0x08, 0x00, 0x00, - 0xA0, 0x6D, 0x0A, 0x00, 0x00, + .rgb332_result = { + .dst_pitch = 5, + .expected = { + 0x0A, 0x08, 0xA0, 0x00, 0x00, + 0x6D, 0x0A, 0x08, 0x00, 0x00, + 0xA0, 0x6D, 0x0A, 0x00, 0x00, + }, + }, + .rgb565_result = { + .dst_pitch = 10, + .expected = { + 0x0A33, 0x1260, 0xA800, 0x0000, 0x0000, + 0x6B8E, 0x0A33, 0x1260, 0x0000, 0x0000, + 0xA800, 0x6B8E, 0x0A33, 0x0000, 0x0000, + }, + .expected_swab = { + 0x330A, 0x6012, 0x00A8, 0x0000, 0x0000, + 0x8E6B, 0x330A, 0x6012, 0x0000, 0x0000, + 0x00A8, 0x8E6B, 0x330A, 0x0000, 0x0000, + }, }, }, }; @@ -111,41 +168,96 @@ static size_t conversion_buf_size(u32 dst_format, unsigned int dst_pitch, return dst_pitch * drm_rect_height(clip); } -static void xrgb8888_to_rgb332_case_desc(struct xrgb8888_to_rgb332_case *t, - char *desc) +static u32 *le32buf_to_cpu(struct kunit *test, const u32 *buf, size_t buf_size) +{ + u32 *dst = NULL; + int n; + + dst = kunit_kzalloc(test, sizeof(*dst) * buf_size, GFP_KERNEL); + if (!dst) + return NULL; + + for (n = 0; n < buf_size; n++) + dst[n] = le32_to_cpu((__force __le32)buf[n]); + + return dst; +} + +static void convert_xrgb8888_case_desc(struct convert_xrgb8888_case *t, + char *desc) { strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); } -KUNIT_ARRAY_PARAM(xrgb8888_to_rgb332, xrgb8888_to_rgb332_cases, - xrgb8888_to_rgb332_case_desc); +KUNIT_ARRAY_PARAM(convert_xrgb8888, convert_xrgb8888_cases, + convert_xrgb8888_case_desc); static void xrgb8888_to_rgb332_test(struct kunit *test) { - const struct xrgb8888_to_rgb332_case *params = test->param_value; + const struct convert_xrgb8888_case *params = test->param_value; + const struct convert_to_rgb332_result *result = ¶ms->rgb332_result; + size_t dst_size; + __u8 *buf = NULL; + __u32 *xrgb8888 = NULL; + struct iosys_map dst, src; + + struct drm_framebuffer fb = { + .format = drm_format_info(DRM_FORMAT_XRGB8888), + .pitches = { params->pitch, 0, 0 }, + }; + + dst_size = conversion_buf_size(DRM_FORMAT_RGB332, result->dst_pitch, + ¶ms->clip); + KUNIT_ASSERT_GT(test, dst_size, 0); + + buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); + iosys_map_set_vaddr(&dst, buf); + + xrgb8888 = le32buf_to_cpu(test, params->xrgb8888, TEST_BUF_SIZE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); + iosys_map_set_vaddr(&src, xrgb8888); + + drm_fb_xrgb8888_to_rgb332(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); + KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0); +} + +static void xrgb8888_to_rgb565_test(struct kunit *test) +{ + const struct convert_xrgb8888_case *params = test->param_value; + const struct convert_to_rgb565_result *result = ¶ms->rgb565_result; size_t dst_size; - __u8 *dst = NULL; + __u16 *buf = NULL; + __u32 *xrgb8888 = NULL; + struct iosys_map dst, src; struct drm_framebuffer fb = { .format = drm_format_info(DRM_FORMAT_XRGB8888), .pitches = { params->pitch, 0, 0 }, }; - dst_size = conversion_buf_size(DRM_FORMAT_RGB332, params->dst_pitch, + dst_size = conversion_buf_size(DRM_FORMAT_RGB565, result->dst_pitch, ¶ms->clip); KUNIT_ASSERT_GT(test, dst_size, 0); - dst = kunit_kzalloc(test, dst_size, GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dst); + buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); + iosys_map_set_vaddr(&dst, buf); + + xrgb8888 = le32buf_to_cpu(test, params->xrgb8888, TEST_BUF_SIZE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); + iosys_map_set_vaddr(&src, xrgb8888); + + drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip, false); + KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0); - drm_fb_xrgb8888_to_rgb332(dst, params->dst_pitch, params->xrgb8888, - &fb, ¶ms->clip); - KUNIT_EXPECT_EQ(test, memcmp(dst, params->expected, dst_size), 0); + drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip, true); + KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected_swab, dst_size), 0); } static struct kunit_case drm_format_helper_test_cases[] = { - KUNIT_CASE_PARAM(xrgb8888_to_rgb332_test, - xrgb8888_to_rgb332_gen_params), + KUNIT_CASE_PARAM(xrgb8888_to_rgb332_test, convert_xrgb8888_gen_params), + KUNIT_CASE_PARAM(xrgb8888_to_rgb565_test, convert_xrgb8888_gen_params), {} }; diff --git a/drivers/gpu/drm/tests/drm_format_test.c b/drivers/gpu/drm/tests/drm_format_test.c new file mode 100644 index 000000000000..afb4bca72187 --- /dev/null +++ b/drivers/gpu/drm/tests/drm_format_test.c @@ -0,0 +1,299 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Test cases for the drm_format functions + * + * Copyright (c) 2022 MaÃra Canal <mairacanal@riseup.net> + */ + +#include <kunit/test.h> + +#include <drm/drm_fourcc.h> + +static void igt_check_drm_format_block_width(struct kunit *test) +{ + const struct drm_format_info *info = NULL; + + /* Test invalid arguments */ + KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, 0)); + KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, -1)); + KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, 1)); + + /* Test 1 plane format */ + info = drm_format_info(DRM_FORMAT_XRGB4444); + KUNIT_EXPECT_TRUE(test, info); + KUNIT_EXPECT_TRUE(test, drm_format_info_block_width(info, 0)); + KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, 1)); + KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, -1)); + + /* Test 2 planes format */ + info = drm_format_info(DRM_FORMAT_NV12); + KUNIT_EXPECT_TRUE(test, info); + KUNIT_EXPECT_TRUE(test, drm_format_info_block_width(info, 0)); + KUNIT_EXPECT_TRUE(test, drm_format_info_block_width(info, 1)); + KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, 2)); + KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, -1)); + + /* Test 3 planes format */ + info = drm_format_info(DRM_FORMAT_YUV422); + KUNIT_EXPECT_TRUE(test, info); + KUNIT_EXPECT_TRUE(test, drm_format_info_block_width(info, 0)); + KUNIT_EXPECT_TRUE(test, drm_format_info_block_width(info, 1)); + KUNIT_EXPECT_TRUE(test, drm_format_info_block_width(info, 2)); + KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, 3)); + KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, -1)); + + /* Test a tiled format */ + info = drm_format_info(DRM_FORMAT_X0L0); + KUNIT_EXPECT_TRUE(test, info); + KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 0), 2); + KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, 1)); + KUNIT_EXPECT_FALSE(test, drm_format_info_block_width(info, -1)); +} + +static void igt_check_drm_format_block_height(struct kunit *test) +{ + const struct drm_format_info *info = NULL; + + /* Test invalid arguments */ + KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, 0)); + KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, -1)); + KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, 1)); + + /* Test 1 plane format */ + info = drm_format_info(DRM_FORMAT_XRGB4444); + KUNIT_EXPECT_TRUE(test, info); + KUNIT_EXPECT_TRUE(test, drm_format_info_block_height(info, 0)); + KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, -1)); + KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, 1)); + + /* Test 2 planes format */ + info = drm_format_info(DRM_FORMAT_NV12); + KUNIT_EXPECT_TRUE(test, info); + KUNIT_EXPECT_TRUE(test, drm_format_info_block_height(info, 0)); + KUNIT_EXPECT_TRUE(test, drm_format_info_block_height(info, 1)); + KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, 2)); + KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, -1)); + + /* Test 3 planes format */ + info = drm_format_info(DRM_FORMAT_YUV422); + KUNIT_EXPECT_TRUE(test, info); + KUNIT_EXPECT_TRUE(test, drm_format_info_block_height(info, 0)); + KUNIT_EXPECT_TRUE(test, drm_format_info_block_height(info, 1)); + KUNIT_EXPECT_TRUE(test, drm_format_info_block_height(info, 2)); + KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, 3)); + KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, -1)); + + /* Test a tiled format */ + info = drm_format_info(DRM_FORMAT_X0L0); + KUNIT_EXPECT_TRUE(test, info); + KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 0), 2); + KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, 1)); + KUNIT_EXPECT_FALSE(test, drm_format_info_block_height(info, -1)); +} + +static void igt_check_drm_format_min_pitch_for_single_plane(struct kunit *test) +{ + const struct drm_format_info *info = NULL; + + /* Test invalid arguments */ + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0)); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0)); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0)); + + /* Test 1 plane 8 bits per pixel format */ + info = drm_format_info(DRM_FORMAT_RGB332); + KUNIT_EXPECT_TRUE(test, info); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0)); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0)); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0)); + + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 1); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 2); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 640), 640); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1024), 1024); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1920), 1920); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 4096), 4096); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 671); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX), + (uint64_t)UINT_MAX); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)), + (uint64_t)(UINT_MAX - 1)); + + /* Test 1 plane 16 bits per pixel format */ + info = drm_format_info(DRM_FORMAT_XRGB4444); + KUNIT_EXPECT_TRUE(test, info); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0)); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0)); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0)); + + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 2); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 4); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 640), 1280); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1024), 2048); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1920), 3840); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 4096), 8192); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 1342); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX), + (uint64_t)UINT_MAX * 2); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)), + (uint64_t)(UINT_MAX - 1) * 2); + + /* Test 1 plane 24 bits per pixel format */ + info = drm_format_info(DRM_FORMAT_RGB888); + KUNIT_EXPECT_TRUE(test, info); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0)); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0)); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0)); + + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 3); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 6); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 640), 1920); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1024), 3072); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1920), 5760); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 4096), 12288); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 2013); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX), + (uint64_t)UINT_MAX * 3); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)), + (uint64_t)(UINT_MAX - 1) * 3); + + /* Test 1 plane 32 bits per pixel format */ + info = drm_format_info(DRM_FORMAT_ABGR8888); + KUNIT_EXPECT_TRUE(test, info); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0)); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0)); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0)); + + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 4); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 8); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 640), 2560); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1024), 4096); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1920), 7680); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 4096), 16384); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 2684); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX), + (uint64_t)UINT_MAX * 4); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)), + (uint64_t)(UINT_MAX - 1) * 4); +} + +static void igt_check_drm_format_min_pitch_for_multi_planar(struct kunit *test) +{ + const struct drm_format_info *info = NULL; + + /* Test 2 planes format */ + info = drm_format_info(DRM_FORMAT_NV12); + KUNIT_EXPECT_TRUE(test, info); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0)); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0)); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0)); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 2, 0)); + + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 1); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 1), 2); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 2); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 1), 2); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 640), 640); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 320), 640); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1024), 1024); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 512), 1024); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1920), 1920); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 960), 1920); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 4096), 4096); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 2048), 4096); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 671); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 336), 672); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX), + (uint64_t)UINT_MAX); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, UINT_MAX / 2 + 1), + (uint64_t)UINT_MAX + 1); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)), + (uint64_t)(UINT_MAX - 1)); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, (UINT_MAX - 1) / 2), + (uint64_t)(UINT_MAX - 1)); + + /* Test 3 planes 8 bits per pixel format */ + info = drm_format_info(DRM_FORMAT_YUV422); + KUNIT_EXPECT_TRUE(test, info); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0)); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0)); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 2, 0)); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0)); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 3, 0)); + + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 1); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 1), 1); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 1), 1); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 2); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 2), 2); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 2), 2); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 640), 640); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 320), 320); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 320), 320); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1024), 1024); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 512), 512); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 512), 512); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1920), 1920); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 960), 960); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 960), 960); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 4096), 4096); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 2048), 2048); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 2048), 2048); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 671); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 336), 336); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 336), 336); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX), + (uint64_t)UINT_MAX); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, UINT_MAX / 2 + 1), + (uint64_t)UINT_MAX / 2 + 1); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, UINT_MAX / 2 + 1), + (uint64_t)UINT_MAX / 2 + 1); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, (UINT_MAX - 1) / 2), + (uint64_t)(UINT_MAX - 1) / 2); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, (UINT_MAX - 1) / 2), + (uint64_t)(UINT_MAX - 1) / 2); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, (UINT_MAX - 1) / 2), + (uint64_t)(UINT_MAX - 1) / 2); +} + +static void igt_check_drm_format_min_pitch_for_tiled_format(struct kunit *test) +{ + const struct drm_format_info *info = NULL; + + /* Test tiled format */ + info = drm_format_info(DRM_FORMAT_X0L2); + KUNIT_EXPECT_TRUE(test, info); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 0, 0)); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, -1, 0)); + KUNIT_EXPECT_FALSE(test, drm_format_info_min_pitch(info, 1, 0)); + + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 2); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 4); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 640), 1280); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1024), 2048); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1920), 3840); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 4096), 8192); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 1342); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX), + (uint64_t)UINT_MAX * 2); + KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX - 1), + (uint64_t)(UINT_MAX - 1) * 2); +} + +static struct kunit_case drm_format_tests[] = { + KUNIT_CASE(igt_check_drm_format_block_width), + KUNIT_CASE(igt_check_drm_format_block_height), + KUNIT_CASE(igt_check_drm_format_min_pitch_for_single_plane), + KUNIT_CASE(igt_check_drm_format_min_pitch_for_multi_planar), + KUNIT_CASE(igt_check_drm_format_min_pitch_for_tiled_format), + { } +}; + +static struct kunit_suite drm_format_test_suite = { + .name = "drm_format", + .test_cases = drm_format_tests, +}; + +kunit_test_suite(drm_format_test_suite); + +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/selftests/test-drm_framebuffer.c b/drivers/gpu/drm/tests/drm_framebuffer_test.c index f6d66285c5fc..ec7a08ba4056 100644 --- a/drivers/gpu/drm/selftests/test-drm_framebuffer.c +++ b/drivers/gpu/drm/tests/drm_framebuffer_test.c @@ -1,9 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 /* * Test cases for the drm_framebuffer functions + * + * Copyright (c) 2022 MaÃra Canal <mairacanal@riseup.net> */ -#include <linux/kernel.h> +#include <kunit/test.h> #include <drm/drm_device.h> #include <drm/drm_mode.h> @@ -12,8 +14,6 @@ #include "../drm_crtc_internal.h" -#include "test-drm_modeset_common.h" - #define MIN_WIDTH 4 #define MAX_WIDTH 4096 #define MIN_HEIGHT 4 @@ -73,12 +73,14 @@ static struct drm_framebuffer_test createbuffer_tests[] = { }, { .buffer_created = 0, .name = "ABGR8888 Out of bound height * pitch combination", .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888, - .handles = { 1, 0, 0 }, .offsets = { UINT_MAX - 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 }, + .handles = { 1, 0, 0 }, .offsets = { UINT_MAX - 1, 0, 0 }, + .pitches = { 4 * MAX_WIDTH, 0, 0 }, } }, { .buffer_created = 1, .name = "ABGR8888 Large buffer offset", .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888, - .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 }, + .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 }, + .pitches = { 4 * MAX_WIDTH, 0, 0 }, } }, { .buffer_created = 1, .name = "ABGR8888 Set DRM_MODE_FB_MODIFIERS without modifiers", @@ -89,11 +91,13 @@ static struct drm_framebuffer_test createbuffer_tests[] = { }, { .buffer_created = 1, .name = "ABGR8888 Valid buffer modifier", .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888, - .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 }, - .flags = DRM_MODE_FB_MODIFIERS, .modifier = { AFBC_FORMAT_MOD_YTR, 0, 0 }, + .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 }, + .pitches = { 4 * MAX_WIDTH, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS, + .modifier = { AFBC_FORMAT_MOD_YTR, 0, 0 }, } }, -{ .buffer_created = 0, .name = "ABGR8888 Invalid buffer modifier(DRM_FORMAT_MOD_SAMSUNG_64_32_TILE)", +{ .buffer_created = 0, + .name = "ABGR8888 Invalid buffer modifier(DRM_FORMAT_MOD_SAMSUNG_64_32_TILE)", .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888, .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS, @@ -143,7 +147,8 @@ static struct drm_framebuffer_test createbuffer_tests[] = { { .buffer_created = 1, .name = "NV12 with DRM_FORMAT_MOD_SAMSUNG_64_32_TILE", .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12, .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS, - .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0 }, + .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, + DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0 }, .pitches = { MAX_WIDTH, MAX_WIDTH, 0 }, } }, @@ -164,7 +169,8 @@ static struct drm_framebuffer_test createbuffer_tests[] = { }, { .buffer_created = 0, .name = "NV12 Handle for inexistent plane", .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12, - .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS, .pitches = { MAX_WIDTH, MAX_WIDTH, 0 }, + .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS, + .pitches = { MAX_WIDTH, MAX_WIDTH, 0 }, } }, { .buffer_created = 1, .name = "NV12 Handle for inexistent plane without DRM_MODE_FB_MODIFIERS", @@ -203,24 +209,29 @@ static struct drm_framebuffer_test createbuffer_tests[] = { }, { .buffer_created = 1, .name = "YVU420 Different buffer offsets/pitches", .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420, - .handles = { 1, 1, 1 }, .offsets = { MAX_WIDTH, MAX_WIDTH + MAX_WIDTH * MAX_HEIGHT, - MAX_WIDTH + 2 * MAX_WIDTH * MAX_HEIGHT }, - .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2) + 1, DIV_ROUND_UP(MAX_WIDTH, 2) + 7 }, + .handles = { 1, 1, 1 }, .offsets = { MAX_WIDTH, MAX_WIDTH + + MAX_WIDTH * MAX_HEIGHT, MAX_WIDTH + 2 * MAX_WIDTH * MAX_HEIGHT }, + .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2) + 1, + DIV_ROUND_UP(MAX_WIDTH, 2) + 7 }, } }, -{ .buffer_created = 0, .name = "YVU420 Modifier set just for plane 0, without DRM_MODE_FB_MODIFIERS", +{ .buffer_created = 0, + .name = "YVU420 Modifier set just for plane 0, without DRM_MODE_FB_MODIFIERS", .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420, .handles = { 1, 1, 1 }, .modifier = { AFBC_FORMAT_MOD_SPARSE, 0, 0 }, .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) }, } }, -{ .buffer_created = 0, .name = "YVU420 Modifier set just for planes 0, 1, without DRM_MODE_FB_MODIFIERS", +{ .buffer_created = 0, + .name = "YVU420 Modifier set just for planes 0, 1, without DRM_MODE_FB_MODIFIERS", .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420, - .handles = { 1, 1, 1 }, .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, 0 }, + .handles = { 1, 1, 1 }, + .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, 0 }, .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) }, } }, -{ .buffer_created = 0, .name = "YVU420 Modifier set just for plane 0, 1, with DRM_MODE_FB_MODIFIERS", +{ .buffer_created = 0, + .name = "YVU420 Modifier set just for plane 0, 1, with DRM_MODE_FB_MODIFIERS", .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420, .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS, .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, 0 }, @@ -230,7 +241,8 @@ static struct drm_framebuffer_test createbuffer_tests[] = { { .buffer_created = 1, .name = "YVU420 Valid modifier", .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420, .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS, - .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE }, + .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, + AFBC_FORMAT_MOD_SPARSE }, .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) }, } }, @@ -245,8 +257,8 @@ static struct drm_framebuffer_test createbuffer_tests[] = { { .buffer_created = 0, .name = "YVU420 Modifier for inexistent plane", .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420, .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS, - .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, - AFBC_FORMAT_MOD_SPARSE }, + .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, + AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE }, .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) }, } }, @@ -276,7 +288,8 @@ static struct drm_framebuffer_test createbuffer_tests[] = { .pitches = { 2 * MAX_WIDTH + 1, 0, 0 } } }, -{ .buffer_created = 1, .name = "X0L2 Offset for inexistent plane, without DRM_MODE_FB_MODIFIERS set", +{ .buffer_created = 1, + .name = "X0L2 Offset for inexistent plane, without DRM_MODE_FB_MODIFIERS set", .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2, .handles = { 1, 0, 0 }, .offsets = { 0, 0, 3 }, .pitches = { 2 * MAX_WIDTH + 1, 0, 0 } @@ -336,15 +349,27 @@ static int execute_drm_mode_fb_cmd2(struct drm_mode_fb_cmd2 *r) return buffer_created; } -int igt_check_drm_framebuffer_create(void *ignored) +static void igt_check_drm_framebuffer_create(struct kunit *test) { int i = 0; for (i = 0; i < ARRAY_SIZE(createbuffer_tests); i++) { - FAIL(createbuffer_tests[i].buffer_created != - execute_drm_mode_fb_cmd2(&createbuffer_tests[i].cmd), + KUNIT_EXPECT_EQ_MSG(test, createbuffer_tests[i].buffer_created, + execute_drm_mode_fb_cmd2(&createbuffer_tests[i].cmd), "Test %d: \"%s\" failed\n", i, createbuffer_tests[i].name); } - - return 0; } + +static struct kunit_case drm_framebuffer_tests[] = { + KUNIT_CASE(igt_check_drm_framebuffer_create), + { } +}; + +static struct kunit_suite drm_framebuffer_test_suite = { + .name = "drm_framebuffer", + .test_cases = drm_framebuffer_tests, +}; + +kunit_test_suite(drm_framebuffer_test_suite); + +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/selftests/test-drm_mm.c b/drivers/gpu/drm/tests/drm_mm_test.c index b768b53c4aee..1e2c1aa524bd 100644 --- a/drivers/gpu/drm/selftests/test-drm_mm.c +++ b/drivers/gpu/drm/tests/drm_mm_test.c @@ -1,11 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Test cases for the drm_mm range manager + * + * Copyright (c) 2022 Arthur Grillo <arthur.grillo@usp.br> */ -#define pr_fmt(fmt) "drm_mm: " fmt +#include <kunit/test.h> -#include <linux/module.h> #include <linux/prime_numbers.h> #include <linux/slab.h> #include <linux/random.h> @@ -16,9 +17,6 @@ #include "../lib/drm_random.h" -#define TESTS "drm_mm_selftests.h" -#include "drm_selftest.h" - static unsigned int random_seed; static unsigned int max_iterations = 8192; static unsigned int max_prime = 128; @@ -45,13 +43,7 @@ static const struct insert_mode { {} }; -static int igt_sanitycheck(void *ignored) -{ - pr_info("%s - ok!\n", __func__); - return 0; -} - -static bool assert_no_holes(const struct drm_mm *mm) +static bool assert_no_holes(struct kunit *test, const struct drm_mm *mm) { struct drm_mm_node *hole; u64 hole_start, __always_unused hole_end; @@ -61,13 +53,14 @@ static bool assert_no_holes(const struct drm_mm *mm) drm_mm_for_each_hole(hole, mm, hole_start, hole_end) count++; if (count) { - pr_err("Expected to find no holes (after reserve), found %lu instead\n", count); + KUNIT_FAIL(test, + "Expected to find no holes (after reserve), found %lu instead\n", count); return false; } drm_mm_for_each_node(hole, mm) { if (drm_mm_hole_follows(hole)) { - pr_err("Hole follows node, expected none!\n"); + KUNIT_FAIL(test, "Hole follows node, expected none!\n"); return false; } } @@ -75,7 +68,7 @@ static bool assert_no_holes(const struct drm_mm *mm) return true; } -static bool assert_one_hole(const struct drm_mm *mm, u64 start, u64 end) +static bool assert_one_hole(struct kunit *test, const struct drm_mm *mm, u64 start, u64 end) { struct drm_mm_node *hole; u64 hole_start, hole_end; @@ -89,62 +82,62 @@ static bool assert_one_hole(const struct drm_mm *mm, u64 start, u64 end) drm_mm_for_each_hole(hole, mm, hole_start, hole_end) { if (start != hole_start || end != hole_end) { if (ok) - pr_err("empty mm has incorrect hole, found (%llx, %llx), expect (%llx, %llx)\n", - hole_start, hole_end, - start, end); + KUNIT_FAIL(test, + "empty mm has incorrect hole, found (%llx, %llx), expect (%llx, %llx)\n", + hole_start, hole_end, start, end); ok = false; } count++; } if (count != 1) { - pr_err("Expected to find one hole, found %lu instead\n", count); + KUNIT_FAIL(test, "Expected to find one hole, found %lu instead\n", count); ok = false; } return ok; } -static bool assert_continuous(const struct drm_mm *mm, u64 size) +static bool assert_continuous(struct kunit *test, const struct drm_mm *mm, u64 size) { struct drm_mm_node *node, *check, *found; unsigned long n; u64 addr; - if (!assert_no_holes(mm)) + if (!assert_no_holes(test, mm)) return false; n = 0; addr = 0; drm_mm_for_each_node(node, mm) { if (node->start != addr) { - pr_err("node[%ld] list out of order, expected %llx found %llx\n", - n, addr, node->start); + KUNIT_FAIL(test, "node[%ld] list out of order, expected %llx found %llx\n", + n, addr, node->start); return false; } if (node->size != size) { - pr_err("node[%ld].size incorrect, expected %llx, found %llx\n", - n, size, node->size); + KUNIT_FAIL(test, "node[%ld].size incorrect, expected %llx, found %llx\n", + n, size, node->size); return false; } if (drm_mm_hole_follows(node)) { - pr_err("node[%ld] is followed by a hole!\n", n); + KUNIT_FAIL(test, "node[%ld] is followed by a hole!\n", n); return false; } found = NULL; drm_mm_for_each_node_in_range(check, mm, addr, addr + size) { if (node != check) { - pr_err("lookup return wrong node, expected start %llx, found %llx\n", - node->start, check->start); + KUNIT_FAIL(test, + "lookup return wrong node, expected start %llx, found %llx\n", + node->start, check->start); return false; } found = check; } if (!found) { - pr_err("lookup failed for node %llx + %llx\n", - addr, size); + KUNIT_FAIL(test, "lookup failed for node %llx + %llx\n", addr, size); return false; } @@ -166,107 +159,96 @@ static u64 misalignment(struct drm_mm_node *node, u64 alignment) return rem; } -static bool assert_node(struct drm_mm_node *node, struct drm_mm *mm, +static bool assert_node(struct kunit *test, struct drm_mm_node *node, struct drm_mm *mm, u64 size, u64 alignment, unsigned long color) { bool ok = true; if (!drm_mm_node_allocated(node) || node->mm != mm) { - pr_err("node not allocated\n"); + KUNIT_FAIL(test, "node not allocated\n"); ok = false; } if (node->size != size) { - pr_err("node has wrong size, found %llu, expected %llu\n", - node->size, size); + KUNIT_FAIL(test, "node has wrong size, found %llu, expected %llu\n", + node->size, size); ok = false; } if (misalignment(node, alignment)) { - pr_err("node is misaligned, start %llx rem %llu, expected alignment %llu\n", - node->start, misalignment(node, alignment), alignment); + KUNIT_FAIL(test, + "node is misaligned, start %llx rem %llu, expected alignment %llu\n", + node->start, misalignment(node, alignment), alignment); ok = false; } if (node->color != color) { - pr_err("node has wrong color, found %lu, expected %lu\n", - node->color, color); + KUNIT_FAIL(test, "node has wrong color, found %lu, expected %lu\n", + node->color, color); ok = false; } return ok; } -#define show_mm(mm) do { \ - struct drm_printer __p = drm_debug_printer(__func__); \ - drm_mm_print((mm), &__p); } while (0) - -static int igt_init(void *ignored) +static void igt_mm_init(struct kunit *test) { const unsigned int size = 4096; struct drm_mm mm; struct drm_mm_node tmp; - int ret = -EINVAL; /* Start with some simple checks on initialising the struct drm_mm */ memset(&mm, 0, sizeof(mm)); - if (drm_mm_initialized(&mm)) { - pr_err("zeroed mm claims to be initialized\n"); - return ret; - } + KUNIT_ASSERT_FALSE_MSG(test, drm_mm_initialized(&mm), + "zeroed mm claims to be initialized\n"); memset(&mm, 0xff, sizeof(mm)); drm_mm_init(&mm, 0, size); if (!drm_mm_initialized(&mm)) { - pr_err("mm claims not to be initialized\n"); + KUNIT_FAIL(test, "mm claims not to be initialized\n"); goto out; } if (!drm_mm_clean(&mm)) { - pr_err("mm not empty on creation\n"); + KUNIT_FAIL(test, "mm not empty on creation\n"); goto out; } /* After creation, it should all be one massive hole */ - if (!assert_one_hole(&mm, 0, size)) { - ret = -EINVAL; + if (!assert_one_hole(test, &mm, 0, size)) { + KUNIT_FAIL(test, ""); goto out; } memset(&tmp, 0, sizeof(tmp)); tmp.start = 0; tmp.size = size; - ret = drm_mm_reserve_node(&mm, &tmp); - if (ret) { - pr_err("failed to reserve whole drm_mm\n"); + if (drm_mm_reserve_node(&mm, &tmp)) { + KUNIT_FAIL(test, "failed to reserve whole drm_mm\n"); goto out; } /* After filling the range entirely, there should be no holes */ - if (!assert_no_holes(&mm)) { - ret = -EINVAL; + if (!assert_no_holes(test, &mm)) { + KUNIT_FAIL(test, ""); goto out; } /* And then after emptying it again, the massive hole should be back */ drm_mm_remove_node(&tmp); - if (!assert_one_hole(&mm, 0, size)) { - ret = -EINVAL; + if (!assert_one_hole(test, &mm, 0, size)) { + KUNIT_FAIL(test, ""); goto out; } out: - if (ret) - show_mm(&mm); drm_mm_takedown(&mm); - return ret; } -static int igt_debug(void *ignored) +static void igt_mm_debug(struct kunit *test) { struct drm_mm mm; struct drm_mm_node nodes[2]; - int ret; /* Create a small drm_mm with a couple of nodes and a few holes, and * check that the debug iterator doesn't explode over a trivial drm_mm. @@ -277,24 +259,15 @@ static int igt_debug(void *ignored) memset(nodes, 0, sizeof(nodes)); nodes[0].start = 512; nodes[0].size = 1024; - ret = drm_mm_reserve_node(&mm, &nodes[0]); - if (ret) { - pr_err("failed to reserve node[0] {start=%lld, size=%lld)\n", - nodes[0].start, nodes[0].size); - return ret; - } + KUNIT_ASSERT_FALSE_MSG(test, drm_mm_reserve_node(&mm, &nodes[0]), + "failed to reserve node[0] {start=%lld, size=%lld)\n", + nodes[0].start, nodes[0].size); nodes[1].size = 1024; nodes[1].start = 4096 - 512 - nodes[1].size; - ret = drm_mm_reserve_node(&mm, &nodes[1]); - if (ret) { - pr_err("failed to reserve node[1] {start=%lld, size=%lld)\n", - nodes[1].start, nodes[1].size); - return ret; - } - - show_mm(&mm); - return 0; + KUNIT_ASSERT_FALSE_MSG(test, drm_mm_reserve_node(&mm, &nodes[1]), + "failed to reserve node[0] {start=%lld, size=%lld)\n", + nodes[0].start, nodes[0].size); } static struct drm_mm_node *set_node(struct drm_mm_node *node, @@ -305,7 +278,7 @@ static struct drm_mm_node *set_node(struct drm_mm_node *node, return node; } -static bool expect_reserve_fail(struct drm_mm *mm, struct drm_mm_node *node) +static bool expect_reserve_fail(struct kunit *test, struct drm_mm *mm, struct drm_mm_node *node) { int err; @@ -314,17 +287,18 @@ static bool expect_reserve_fail(struct drm_mm *mm, struct drm_mm_node *node) return true; if (!err) { - pr_err("impossible reserve succeeded, node %llu + %llu\n", - node->start, node->size); + KUNIT_FAIL(test, "impossible reserve succeeded, node %llu + %llu\n", + node->start, node->size); drm_mm_remove_node(node); } else { - pr_err("impossible reserve failed with wrong error %d [expected %d], node %llu + %llu\n", + KUNIT_FAIL(test, + "impossible reserve failed with wrong error %d [expected %d], node %llu + %llu\n", err, -ENOSPC, node->start, node->size); } return false; } -static bool check_reserve_boundaries(struct drm_mm *mm, +static bool check_reserve_boundaries(struct kunit *test, struct drm_mm *mm, unsigned int count, u64 size) { @@ -339,29 +313,27 @@ static bool check_reserve_boundaries(struct drm_mm *mm, B(size * count, 0), B(-size, size), B(-size, -size), - B(-size, 2*size), + B(-size, 2 * size), B(0, -size), B(size, -size), - B(count*size, size), - B(count*size, -size), - B(count*size, count*size), - B(count*size, -count*size), - B(count*size, -(count+1)*size), - B((count+1)*size, size), - B((count+1)*size, -size), - B((count+1)*size, -2*size), + B(count * size, size), + B(count * size, -size), + B(count * size, count * size), + B(count * size, -count * size), + B(count * size, -(count + 1) * size), + B((count + 1) * size, size), + B((count + 1) * size, -size), + B((count + 1) * size, -2 * size), #undef B }; struct drm_mm_node tmp = {}; int n; for (n = 0; n < ARRAY_SIZE(boundaries); n++) { - if (!expect_reserve_fail(mm, - set_node(&tmp, - boundaries[n].start, - boundaries[n].size))) { - pr_err("boundary[%d:%s] failed, count=%u, size=%lld\n", - n, boundaries[n].name, count, size); + if (!expect_reserve_fail(test, mm, set_node(&tmp, boundaries[n].start, + boundaries[n].size))) { + KUNIT_FAIL(test, "boundary[%d:%s] failed, count=%u, size=%lld\n", + n, boundaries[n].name, count, size); return false; } } @@ -369,7 +341,7 @@ static bool check_reserve_boundaries(struct drm_mm *mm, return true; } -static int __igt_reserve(unsigned int count, u64 size) +static int __igt_reserve(struct kunit *test, unsigned int count, u64 size) { DRM_RND_STATE(prng, random_seed); struct drm_mm mm; @@ -377,7 +349,7 @@ static int __igt_reserve(unsigned int count, u64 size) unsigned int *order, n, m, o = 0; int ret, err; - /* For exercising drm_mm_reserve_node(), we want to check that + /* For exercising drm_mm_reserve_node(struct kunit *test, ), we want to check that * reservations outside of the drm_mm range are rejected, and to * overlapping and otherwise already occupied ranges. Afterwards, * the tree and nodes should be intact. @@ -392,13 +364,12 @@ static int __igt_reserve(unsigned int count, u64 size) goto err; nodes = vzalloc(array_size(count, sizeof(*nodes))); - if (!nodes) - goto err_order; + KUNIT_ASSERT_TRUE(test, nodes); ret = -EINVAL; drm_mm_init(&mm, 0, count * size); - if (!check_reserve_boundaries(&mm, count, size)) + if (!check_reserve_boundaries(test, &mm, count, size)) goto out; for (n = 0; n < count; n++) { @@ -407,57 +378,53 @@ static int __igt_reserve(unsigned int count, u64 size) err = drm_mm_reserve_node(&mm, &nodes[n]); if (err) { - pr_err("reserve failed, step %d, start %llu\n", - n, nodes[n].start); + KUNIT_FAIL(test, "reserve failed, step %d, start %llu\n", + n, nodes[n].start); ret = err; goto out; } if (!drm_mm_node_allocated(&nodes[n])) { - pr_err("reserved node not allocated! step %d, start %llu\n", - n, nodes[n].start); + KUNIT_FAIL(test, "reserved node not allocated! step %d, start %llu\n", + n, nodes[n].start); goto out; } - if (!expect_reserve_fail(&mm, &nodes[n])) + if (!expect_reserve_fail(test, &mm, &nodes[n])) goto out; } /* After random insertion the nodes should be in order */ - if (!assert_continuous(&mm, size)) + if (!assert_continuous(test, &mm, size)) goto out; /* Repeated use should then fail */ drm_random_reorder(order, count, &prng); for (n = 0; n < count; n++) { - if (!expect_reserve_fail(&mm, - set_node(&tmp, order[n] * size, 1))) + if (!expect_reserve_fail(test, &mm, set_node(&tmp, order[n] * size, 1))) goto out; /* Remove and reinsert should work */ drm_mm_remove_node(&nodes[order[n]]); err = drm_mm_reserve_node(&mm, &nodes[order[n]]); if (err) { - pr_err("reserve failed, step %d, start %llu\n", - n, nodes[n].start); + KUNIT_FAIL(test, "reserve failed, step %d, start %llu\n", + n, nodes[n].start); ret = err; goto out; } } - if (!assert_continuous(&mm, size)) + if (!assert_continuous(test, &mm, size)) goto out; /* Overlapping use should then fail */ for (n = 0; n < count; n++) { - if (!expect_reserve_fail(&mm, set_node(&tmp, 0, size*count))) + if (!expect_reserve_fail(test, &mm, set_node(&tmp, 0, size * count))) goto out; } for (n = 0; n < count; n++) { - if (!expect_reserve_fail(&mm, - set_node(&tmp, - size * n, - size * (count - n)))) + if (!expect_reserve_fail(test, &mm, set_node(&tmp, size * n, size * (count - n)))) goto out; } @@ -472,8 +439,8 @@ static int __igt_reserve(unsigned int count, u64 size) node = &nodes[order[(o + m) % count]]; err = drm_mm_reserve_node(&mm, node); if (err) { - pr_err("reserve failed, step %d/%d, start %llu\n", - m, n, node->start); + KUNIT_FAIL(test, "reserve failed, step %d/%d, start %llu\n", + m, n, node->start); ret = err; goto out; } @@ -481,7 +448,7 @@ static int __igt_reserve(unsigned int count, u64 size) o += n; - if (!assert_continuous(&mm, size)) + if (!assert_continuous(test, &mm, size)) goto out; } @@ -491,41 +458,30 @@ out: drm_mm_remove_node(node); drm_mm_takedown(&mm); vfree(nodes); -err_order: kfree(order); err: return ret; } -static int igt_reserve(void *ignored) +static void igt_mm_reserve(struct kunit *test) { const unsigned int count = min_t(unsigned int, BIT(10), max_iterations); - int n, ret; + int n; for_each_prime_number_from(n, 1, 54) { u64 size = BIT_ULL(n); - ret = __igt_reserve(count, size - 1); - if (ret) - return ret; - - ret = __igt_reserve(count, size); - if (ret) - return ret; - - ret = __igt_reserve(count, size + 1); - if (ret) - return ret; + KUNIT_ASSERT_FALSE(test, __igt_reserve(test, count, size - 1)); + KUNIT_ASSERT_FALSE(test, __igt_reserve(test, count, size)); + KUNIT_ASSERT_FALSE(test, __igt_reserve(test, count, size + 1)); cond_resched(); } - - return 0; } -static bool expect_insert(struct drm_mm *mm, struct drm_mm_node *node, - u64 size, u64 alignment, unsigned long color, - const struct insert_mode *mode) +static bool expect_insert(struct kunit *test, struct drm_mm *mm, + struct drm_mm_node *node, u64 size, u64 alignment, unsigned long color, + const struct insert_mode *mode) { int err; @@ -533,12 +489,13 @@ static bool expect_insert(struct drm_mm *mm, struct drm_mm_node *node, size, alignment, color, mode->mode); if (err) { - pr_err("insert (size=%llu, alignment=%llu, color=%lu, mode=%s) failed with err=%d\n", - size, alignment, color, mode->name, err); + KUNIT_FAIL(test, + "insert (size=%llu, alignment=%llu, color=%lu, mode=%s) failed with err=%d\n", + size, alignment, color, mode->name, err); return false; } - if (!assert_node(node, mm, size, alignment, color)) { + if (!assert_node(test, node, mm, size, alignment, color)) { drm_mm_remove_node(node); return false; } @@ -546,7 +503,7 @@ static bool expect_insert(struct drm_mm *mm, struct drm_mm_node *node, return true; } -static bool expect_insert_fail(struct drm_mm *mm, u64 size) +static bool expect_insert_fail(struct kunit *test, struct drm_mm *mm, u64 size) { struct drm_mm_node tmp = {}; int err; @@ -556,17 +513,18 @@ static bool expect_insert_fail(struct drm_mm *mm, u64 size) return true; if (!err) { - pr_err("impossible insert succeeded, node %llu + %llu\n", - tmp.start, tmp.size); + KUNIT_FAIL(test, "impossible insert succeeded, node %llu + %llu\n", + tmp.start, tmp.size); drm_mm_remove_node(&tmp); } else { - pr_err("impossible insert failed with wrong error %d [expected %d], size %llu\n", - err, -ENOSPC, size); + KUNIT_FAIL(test, + "impossible insert failed with wrong error %d [expected %d], size %llu\n", + err, -ENOSPC, size); } return false; } -static int __igt_insert(unsigned int count, u64 size, bool replace) +static int __igt_insert(struct kunit *test, unsigned int count, u64 size, bool replace) { DRM_RND_STATE(prng, random_seed); const struct insert_mode *mode; @@ -582,8 +540,7 @@ static int __igt_insert(unsigned int count, u64 size, bool replace) ret = -ENOMEM; nodes = vmalloc(array_size(count, sizeof(*nodes))); - if (!nodes) - goto err; + KUNIT_ASSERT_TRUE(test, nodes); order = drm_random_order(count, &prng); if (!order) @@ -598,41 +555,43 @@ static int __igt_insert(unsigned int count, u64 size, bool replace) node = replace ? &tmp : &nodes[n]; memset(node, 0, sizeof(*node)); - if (!expect_insert(&mm, node, size, 0, n, mode)) { - pr_err("%s insert failed, size %llu step %d\n", - mode->name, size, n); + if (!expect_insert(test, &mm, node, size, 0, n, mode)) { + KUNIT_FAIL(test, "%s insert failed, size %llu step %d\n", + mode->name, size, n); goto out; } if (replace) { drm_mm_replace_node(&tmp, &nodes[n]); if (drm_mm_node_allocated(&tmp)) { - pr_err("replaced old-node still allocated! step %d\n", - n); + KUNIT_FAIL(test, + "replaced old-node still allocated! step %d\n", + n); goto out; } - if (!assert_node(&nodes[n], &mm, size, 0, n)) { - pr_err("replaced node did not inherit parameters, size %llu step %d\n", - size, n); + if (!assert_node(test, &nodes[n], &mm, size, 0, n)) { + KUNIT_FAIL(test, + "replaced node did not inherit parameters, size %llu step %d\n", + size, n); goto out; } if (tmp.start != nodes[n].start) { - pr_err("replaced node mismatch location expected [%llx + %llx], found [%llx + %llx]\n", - tmp.start, size, - nodes[n].start, nodes[n].size); + KUNIT_FAIL(test, + "replaced node mismatch location expected [%llx + %llx], found [%llx + %llx]\n", + tmp.start, size, nodes[n].start, nodes[n].size); goto out; } } } /* After random insertion the nodes should be in order */ - if (!assert_continuous(&mm, size)) + if (!assert_continuous(test, &mm, size)) goto out; /* Repeated use should then fail */ - if (!expect_insert_fail(&mm, size)) + if (!expect_insert_fail(test, &mm, size)) goto out; /* Remove one and reinsert, as the only hole it should refill itself */ @@ -640,19 +599,20 @@ static int __igt_insert(unsigned int count, u64 size, bool replace) u64 addr = nodes[n].start; drm_mm_remove_node(&nodes[n]); - if (!expect_insert(&mm, &nodes[n], size, 0, n, mode)) { - pr_err("%s reinsert failed, size %llu step %d\n", - mode->name, size, n); + if (!expect_insert(test, &mm, &nodes[n], size, 0, n, mode)) { + KUNIT_FAIL(test, "%s reinsert failed, size %llu step %d\n", + mode->name, size, n); goto out; } if (nodes[n].start != addr) { - pr_err("%s reinsert node moved, step %d, expected %llx, found %llx\n", - mode->name, n, addr, nodes[n].start); + KUNIT_FAIL(test, + "%s reinsert node moved, step %d, expected %llx, found %llx\n", + mode->name, n, addr, nodes[n].start); goto out; } - if (!assert_continuous(&mm, size)) + if (!assert_continuous(test, &mm, size)) goto out; } @@ -665,19 +625,20 @@ static int __igt_insert(unsigned int count, u64 size, bool replace) for (m = 0; m < n; m++) { node = &nodes[order[(o + m) % count]]; - if (!expect_insert(&mm, node, size, 0, n, mode)) { - pr_err("%s multiple reinsert failed, size %llu step %d\n", - mode->name, size, n); + if (!expect_insert(test, &mm, node, size, 0, n, mode)) { + KUNIT_FAIL(test, + "%s multiple reinsert failed, size %llu step %d\n", + mode->name, size, n); goto out; } } o += n; - if (!assert_continuous(&mm, size)) + if (!assert_continuous(test, &mm, size)) goto out; - if (!expect_insert_fail(&mm, size)) + if (!expect_insert_fail(test, &mm, size)) goto out; } @@ -696,42 +657,29 @@ out: kfree(order); err_nodes: vfree(nodes); -err: return ret; } -static int igt_insert(void *ignored) +static void igt_mm_insert(struct kunit *test) { const unsigned int count = min_t(unsigned int, BIT(10), max_iterations); unsigned int n; - int ret; for_each_prime_number_from(n, 1, 54) { u64 size = BIT_ULL(n); - ret = __igt_insert(count, size - 1, false); - if (ret) - return ret; - - ret = __igt_insert(count, size, false); - if (ret) - return ret; - - ret = __igt_insert(count, size + 1, false); - if (ret) - return ret; + KUNIT_ASSERT_FALSE(test, __igt_insert(test, count, size - 1, false)); + KUNIT_ASSERT_FALSE(test, __igt_insert(test, count, size, false)); + KUNIT_ASSERT_FALSE(test, __igt_insert(test, count, size + 1, false)); cond_resched(); } - - return 0; } -static int igt_replace(void *ignored) +static void igt_mm_replace(struct kunit *test) { const unsigned int count = min_t(unsigned int, BIT(10), max_iterations); unsigned int n; - int ret; /* Reuse igt_insert to exercise replacement by inserting a dummy node, * then replacing it with the intended node. We want to check that @@ -742,28 +690,17 @@ static int igt_replace(void *ignored) for_each_prime_number_from(n, 1, 54) { u64 size = BIT_ULL(n); - ret = __igt_insert(count, size - 1, true); - if (ret) - return ret; - - ret = __igt_insert(count, size, true); - if (ret) - return ret; - - ret = __igt_insert(count, size + 1, true); - if (ret) - return ret; + KUNIT_ASSERT_FALSE(test, __igt_insert(test, count, size - 1, true)); + KUNIT_ASSERT_FALSE(test, __igt_insert(test, count, size, true)); + KUNIT_ASSERT_FALSE(test, __igt_insert(test, count, size + 1, true)); cond_resched(); } - - return 0; } -static bool expect_insert_in_range(struct drm_mm *mm, struct drm_mm_node *node, +static bool expect_insert_in_range(struct kunit *test, struct drm_mm *mm, struct drm_mm_node *node, u64 size, u64 alignment, unsigned long color, - u64 range_start, u64 range_end, - const struct insert_mode *mode) + u64 range_start, u64 range_end, const struct insert_mode *mode) { int err; @@ -772,13 +709,14 @@ static bool expect_insert_in_range(struct drm_mm *mm, struct drm_mm_node *node, range_start, range_end, mode->mode); if (err) { - pr_err("insert (size=%llu, alignment=%llu, color=%lu, mode=%s) nto range [%llx, %llx] failed with err=%d\n", - size, alignment, color, mode->name, - range_start, range_end, err); + KUNIT_FAIL(test, + "insert (size=%llu, alignment=%llu, color=%lu, mode=%s) nto range [%llx, %llx] failed with err=%d\n", + size, alignment, color, mode->name, + range_start, range_end, err); return false; } - if (!assert_node(node, mm, size, alignment, color)) { + if (!assert_node(test, node, mm, size, alignment, color)) { drm_mm_remove_node(node); return false; } @@ -786,67 +724,63 @@ static bool expect_insert_in_range(struct drm_mm *mm, struct drm_mm_node *node, return true; } -static bool expect_insert_in_range_fail(struct drm_mm *mm, - u64 size, - u64 range_start, - u64 range_end) +static bool expect_insert_in_range_fail(struct kunit *test, struct drm_mm *mm, + u64 size, u64 range_start, u64 range_end) { struct drm_mm_node tmp = {}; int err; - err = drm_mm_insert_node_in_range(mm, &tmp, - size, 0, 0, - range_start, range_end, + err = drm_mm_insert_node_in_range(mm, &tmp, size, 0, 0, range_start, range_end, 0); if (likely(err == -ENOSPC)) return true; if (!err) { - pr_err("impossible insert succeeded, node %llx + %llu, range [%llx, %llx]\n", - tmp.start, tmp.size, range_start, range_end); + KUNIT_FAIL(test, + "impossible insert succeeded, node %llx + %llu, range [%llx, %llx]\n", + tmp.start, tmp.size, range_start, range_end); drm_mm_remove_node(&tmp); } else { - pr_err("impossible insert failed with wrong error %d [expected %d], size %llu, range [%llx, %llx]\n", - err, -ENOSPC, size, range_start, range_end); + KUNIT_FAIL(test, + "impossible insert failed with wrong error %d [expected %d], size %llu, range [%llx, %llx]\n", + err, -ENOSPC, size, range_start, range_end); } return false; } -static bool assert_contiguous_in_range(struct drm_mm *mm, - u64 size, - u64 start, - u64 end) +static bool assert_contiguous_in_range(struct kunit *test, struct drm_mm *mm, + u64 size, u64 start, u64 end) { struct drm_mm_node *node; unsigned int n; - if (!expect_insert_in_range_fail(mm, size, start, end)) + if (!expect_insert_in_range_fail(test, mm, size, start, end)) return false; n = div64_u64(start + size - 1, size); drm_mm_for_each_node(node, mm) { if (node->start < start || node->start + node->size > end) { - pr_err("node %d out of range, address [%llx + %llu], range [%llx, %llx]\n", - n, node->start, node->start + node->size, start, end); + KUNIT_FAIL(test, + "node %d out of range, address [%llx + %llu], range [%llx, %llx]\n", + n, node->start, node->start + node->size, start, end); return false; } if (node->start != n * size) { - pr_err("node %d out of order, expected start %llx, found %llx\n", - n, n * size, node->start); + KUNIT_FAIL(test, "node %d out of order, expected start %llx, found %llx\n", + n, n * size, node->start); return false; } if (node->size != size) { - pr_err("node %d has wrong size, expected size %llx, found %llx\n", - n, size, node->size); + KUNIT_FAIL(test, "node %d has wrong size, expected size %llx, found %llx\n", + n, size, node->size); return false; } - if (drm_mm_hole_follows(node) && - drm_mm_hole_node_end(node) < end) { - pr_err("node %d is followed by a hole!\n", n); + if (drm_mm_hole_follows(node) && drm_mm_hole_node_end(node) < end) { + KUNIT_FAIL(test, "node %d is followed by a hole!\n", n); return false; } @@ -856,8 +790,8 @@ static bool assert_contiguous_in_range(struct drm_mm *mm, if (start > 0) { node = __drm_mm_interval_first(mm, 0, start - 1); if (drm_mm_node_allocated(node)) { - pr_err("node before start: node=%llx+%llu, start=%llx\n", - node->start, node->size, start); + KUNIT_FAIL(test, "node before start: node=%llx+%llu, start=%llx\n", + node->start, node->size, start); return false; } } @@ -865,8 +799,8 @@ static bool assert_contiguous_in_range(struct drm_mm *mm, if (end < U64_MAX) { node = __drm_mm_interval_first(mm, end, U64_MAX); if (drm_mm_node_allocated(node)) { - pr_err("node after end: node=%llx+%llu, end=%llx\n", - node->start, node->size, end); + KUNIT_FAIL(test, "node after end: node=%llx+%llu, end=%llx\n", + node->start, node->size, end); return false; } } @@ -874,7 +808,7 @@ static bool assert_contiguous_in_range(struct drm_mm *mm, return true; } -static int __igt_insert_range(unsigned int count, u64 size, u64 start, u64 end) +static int __igt_insert_range(struct kunit *test, unsigned int count, u64 size, u64 start, u64 end) { const struct insert_mode *mode; struct drm_mm mm; @@ -886,14 +820,13 @@ static int __igt_insert_range(unsigned int count, u64 size, u64 start, u64 end) DRM_MM_BUG_ON(!size); DRM_MM_BUG_ON(end <= start); - /* Very similar to __igt_insert(), but now instead of populating the + /* Very similar to __igt_insert(struct kunit *test, ), but now instead of populating the * full range of the drm_mm, we try to fill a small portion of it. */ ret = -ENOMEM; nodes = vzalloc(array_size(count, sizeof(*nodes))); - if (!nodes) - goto err; + KUNIT_ASSERT_TRUE(test, nodes); ret = -EINVAL; drm_mm_init(&mm, 0, count * size); @@ -903,20 +836,19 @@ static int __igt_insert_range(unsigned int count, u64 size, u64 start, u64 end) for (mode = insert_modes; mode->name; mode++) { for (n = start_n; n <= end_n; n++) { - if (!expect_insert_in_range(&mm, &nodes[n], - size, size, n, + if (!expect_insert_in_range(test, &mm, &nodes[n], size, size, n, start, end, mode)) { - pr_err("%s insert failed, size %llu, step %d [%d, %d], range [%llx, %llx]\n", - mode->name, size, n, - start_n, end_n, - start, end); + KUNIT_FAIL(test, + "%s insert failed, size %llu, step %d [%d, %d], range [%llx, %llx]\n", + mode->name, size, n, start_n, end_n, start, end); goto out; } } - if (!assert_contiguous_in_range(&mm, size, start, end)) { - pr_err("%s: range [%llx, %llx] not full after initialisation, size=%llu\n", - mode->name, start, end, size); + if (!assert_contiguous_in_range(test, &mm, size, start, end)) { + KUNIT_FAIL(test, + "%s: range [%llx, %llx] not full after initialisation, size=%llu\n", + mode->name, start, end, size); goto out; } @@ -925,23 +857,24 @@ static int __igt_insert_range(unsigned int count, u64 size, u64 start, u64 end) u64 addr = nodes[n].start; drm_mm_remove_node(&nodes[n]); - if (!expect_insert_in_range(&mm, &nodes[n], - size, size, n, + if (!expect_insert_in_range(test, &mm, &nodes[n], size, size, n, start, end, mode)) { - pr_err("%s reinsert failed, step %d\n", mode->name, n); + KUNIT_FAIL(test, "%s reinsert failed, step %d\n", mode->name, n); goto out; } if (nodes[n].start != addr) { - pr_err("%s reinsert node moved, step %d, expected %llx, found %llx\n", - mode->name, n, addr, nodes[n].start); + KUNIT_FAIL(test, + "%s reinsert node moved, step %d, expected %llx, found %llx\n", + mode->name, n, addr, nodes[n].start); goto out; } } - if (!assert_contiguous_in_range(&mm, size, start, end)) { - pr_err("%s: range [%llx, %llx] not full after reinsertion, size=%llu\n", - mode->name, start, end, size); + if (!assert_contiguous_in_range(test, &mm, size, start, end)) { + KUNIT_FAIL(test, + "%s: range [%llx, %llx] not full after reinsertion, size=%llu\n", + mode->name, start, end, size); goto out; } @@ -958,11 +891,10 @@ out: drm_mm_remove_node(node); drm_mm_takedown(&mm); vfree(nodes); -err: return ret; } -static int insert_outside_range(void) +static int insert_outside_range(struct kunit *test) { struct drm_mm mm; const unsigned int start = 1024; @@ -971,81 +903,58 @@ static int insert_outside_range(void) drm_mm_init(&mm, start, size); - if (!expect_insert_in_range_fail(&mm, 1, 0, start)) + if (!expect_insert_in_range_fail(test, &mm, 1, 0, start)) return -EINVAL; - if (!expect_insert_in_range_fail(&mm, size, - start - size/2, start + (size+1)/2)) + if (!expect_insert_in_range_fail(test, &mm, size, + start - size / 2, start + (size + 1) / 2)) return -EINVAL; - if (!expect_insert_in_range_fail(&mm, size, - end - (size+1)/2, end + size/2)) + if (!expect_insert_in_range_fail(test, &mm, size, + end - (size + 1) / 2, end + size / 2)) return -EINVAL; - if (!expect_insert_in_range_fail(&mm, 1, end, end + size)) + if (!expect_insert_in_range_fail(test, &mm, 1, end, end + size)) return -EINVAL; drm_mm_takedown(&mm); return 0; } -static int igt_insert_range(void *ignored) +static void igt_mm_insert_range(struct kunit *test) { const unsigned int count = min_t(unsigned int, BIT(13), max_iterations); unsigned int n; - int ret; /* Check that requests outside the bounds of drm_mm are rejected. */ - ret = insert_outside_range(); - if (ret) - return ret; + KUNIT_ASSERT_FALSE(test, insert_outside_range(test)); for_each_prime_number_from(n, 1, 50) { const u64 size = BIT_ULL(n); const u64 max = count * size; - ret = __igt_insert_range(count, size, 0, max); - if (ret) - return ret; - - ret = __igt_insert_range(count, size, 1, max); - if (ret) - return ret; - - ret = __igt_insert_range(count, size, 0, max - 1); - if (ret) - return ret; - - ret = __igt_insert_range(count, size, 0, max/2); - if (ret) - return ret; - - ret = __igt_insert_range(count, size, max/2, max); - if (ret) - return ret; - - ret = __igt_insert_range(count, size, max/4+1, 3*max/4-1); - if (ret) - return ret; + KUNIT_ASSERT_FALSE(test, __igt_insert_range(test, count, size, 0, max)); + KUNIT_ASSERT_FALSE(test, __igt_insert_range(test, count, size, 1, max)); + KUNIT_ASSERT_FALSE(test, __igt_insert_range(test, count, size, 0, max - 1)); + KUNIT_ASSERT_FALSE(test, __igt_insert_range(test, count, size, 0, max / 2)); + KUNIT_ASSERT_FALSE(test, __igt_insert_range(test, count, size, max / 2, max / 2)); + KUNIT_ASSERT_FALSE(test, __igt_insert_range(test, count, size, + max / 4 + 1, 3 * max / 4 - 1)); cond_resched(); } - - return 0; } -static int prepare_igt_frag(struct drm_mm *mm, - struct drm_mm_node *nodes, - unsigned int num_insert, +static int prepare_igt_frag(struct kunit *test, struct drm_mm *mm, + struct drm_mm_node *nodes, unsigned int num_insert, const struct insert_mode *mode) { unsigned int size = 4096; unsigned int i; for (i = 0; i < num_insert; i++) { - if (!expect_insert(mm, &nodes[i], size, 0, i, - mode) != 0) { - pr_err("%s insert failed\n", mode->name); + if (!expect_insert(test, mm, &nodes[i], size, 0, i, mode) != 0) { + KUNIT_FAIL(test, "%s insert failed\n", mode->name); return -EINVAL; } } @@ -1057,12 +966,10 @@ static int prepare_igt_frag(struct drm_mm *mm, } return 0; - } -static u64 get_insert_time(struct drm_mm *mm, - unsigned int num_insert, - struct drm_mm_node *nodes, +static u64 get_insert_time(struct kunit *test, struct drm_mm *mm, + unsigned int num_insert, struct drm_mm_node *nodes, const struct insert_mode *mode) { unsigned int size = 8192; @@ -1071,8 +978,8 @@ static u64 get_insert_time(struct drm_mm *mm, start = ktime_get(); for (i = 0; i < num_insert; i++) { - if (!expect_insert(mm, &nodes[i], size, 0, i, mode) != 0) { - pr_err("%s insert failed\n", mode->name); + if (!expect_insert(test, mm, &nodes[i], size, 0, i, mode) != 0) { + KUNIT_FAIL(test, "%s insert failed\n", mode->name); return 0; } } @@ -1080,28 +987,26 @@ static u64 get_insert_time(struct drm_mm *mm, return ktime_to_ns(ktime_sub(ktime_get(), start)); } -static int igt_frag(void *ignored) +static void igt_mm_frag(struct kunit *test) { struct drm_mm mm; const struct insert_mode *mode; struct drm_mm_node *nodes, *node, *next; unsigned int insert_size = 10000; unsigned int scale_factor = 4; - int ret = -EINVAL; /* We need 4 * insert_size nodes to hold intermediate allocated * drm_mm nodes. - * 1 times for prepare_igt_frag() - * 1 times for get_insert_time() - * 2 times for get_insert_time() + * 1 times for prepare_igt_frag(struct kunit *test, ) + * 1 times for get_insert_time(struct kunit *test, ) + * 2 times for get_insert_time(struct kunit *test, ) */ nodes = vzalloc(array_size(insert_size * 4, sizeof(*nodes))); - if (!nodes) - return -ENOMEM; + KUNIT_ASSERT_TRUE(test, nodes); /* For BOTTOMUP and TOPDOWN, we first fragment the - * address space using prepare_igt_frag() and then try to verify - * that that insertions scale quadratically from 10k to 20k insertions + * address space using prepare_igt_frag(struct kunit *test, ) and then try to verify + * that insertions scale quadratically from 10k to 20k insertions */ drm_mm_init(&mm, 1, U64_MAX - 2); for (mode = insert_modes; mode->name; mode++) { @@ -1111,28 +1016,25 @@ static int igt_frag(void *ignored) mode->mode != DRM_MM_INSERT_HIGH) continue; - ret = prepare_igt_frag(&mm, nodes, insert_size, mode); - if (ret) + if (prepare_igt_frag(test, &mm, nodes, insert_size, mode)) goto err; - insert_time1 = get_insert_time(&mm, insert_size, + insert_time1 = get_insert_time(test, &mm, insert_size, nodes + insert_size, mode); if (insert_time1 == 0) goto err; - insert_time2 = get_insert_time(&mm, (insert_size * 2), + insert_time2 = get_insert_time(test, &mm, (insert_size * 2), nodes + insert_size * 2, mode); if (insert_time2 == 0) goto err; - pr_info("%s fragmented insert of %u and %u insertions took %llu and %llu nsecs\n", - mode->name, insert_size, insert_size * 2, - insert_time1, insert_time2); + kunit_info(test, "%s fragmented insert of %u and %u insertions took %llu and %llu nsecs\n", + mode->name, insert_size, insert_size * 2, insert_time1, insert_time2); if (insert_time2 > (scale_factor * insert_time1)) { - pr_err("%s fragmented insert took %llu nsecs more\n", - mode->name, - insert_time2 - (scale_factor * insert_time1)); + KUNIT_FAIL(test, "%s fragmented insert took %llu nsecs more\n", + mode->name, insert_time2 - (scale_factor * insert_time1)); goto err; } @@ -1140,24 +1042,20 @@ static int igt_frag(void *ignored) drm_mm_remove_node(node); } - ret = 0; err: drm_mm_for_each_node_safe(node, next, &mm) drm_mm_remove_node(node); drm_mm_takedown(&mm); vfree(nodes); - - return ret; } -static int igt_align(void *ignored) +static void igt_mm_align(struct kunit *test) { const struct insert_mode *mode; const unsigned int max_count = min(8192u, max_prime); struct drm_mm mm; struct drm_mm_node *nodes, *node, *next; unsigned int prime; - int ret = -EINVAL; /* For each of the possible insertion modes, we pick a few * arbitrary alignments and check that the inserted node @@ -1165,8 +1063,7 @@ static int igt_align(void *ignored) */ nodes = vzalloc(array_size(max_count, sizeof(*nodes))); - if (!nodes) - goto err; + KUNIT_ASSERT_TRUE(test, nodes); drm_mm_init(&mm, 1, U64_MAX - 2); @@ -1176,11 +1073,9 @@ static int igt_align(void *ignored) for_each_prime_number_from(prime, 1, max_count) { u64 size = next_prime_number(prime); - if (!expect_insert(&mm, &nodes[i], - size, prime, i, - mode)) { - pr_err("%s insert failed with alignment=%d", - mode->name, prime); + if (!expect_insert(test, &mm, &nodes[i], size, prime, i, mode)) { + KUNIT_FAIL(test, "%s insert failed with alignment=%d", + mode->name, prime); goto out; } @@ -1194,22 +1089,18 @@ static int igt_align(void *ignored) cond_resched(); } - ret = 0; out: drm_mm_for_each_node_safe(node, next, &mm) drm_mm_remove_node(node); drm_mm_takedown(&mm); vfree(nodes); -err: - return ret; } -static int igt_align_pot(int max) +static void igt_align_pot(struct kunit *test, int max) { struct drm_mm mm; struct drm_mm_node *node, *next; int bit; - int ret = -EINVAL; /* Check that we can align to the full u64 address space */ @@ -1220,51 +1111,45 @@ static int igt_align_pot(int max) node = kzalloc(sizeof(*node), GFP_KERNEL); if (!node) { - ret = -ENOMEM; + KUNIT_FAIL(test, "failed to allocate node"); goto out; } align = BIT_ULL(bit); - size = BIT_ULL(bit-1) + 1; - if (!expect_insert(&mm, node, - size, align, bit, - &insert_modes[0])) { - pr_err("insert failed with alignment=%llx [%d]", - align, bit); + size = BIT_ULL(bit - 1) + 1; + if (!expect_insert(test, &mm, node, size, align, bit, &insert_modes[0])) { + KUNIT_FAIL(test, "insert failed with alignment=%llx [%d]", align, bit); goto out; } cond_resched(); } - ret = 0; out: drm_mm_for_each_node_safe(node, next, &mm) { drm_mm_remove_node(node); kfree(node); } drm_mm_takedown(&mm); - return ret; } -static int igt_align32(void *ignored) +static void igt_mm_align32(struct kunit *test) { - return igt_align_pot(32); + igt_align_pot(test, 32); } -static int igt_align64(void *ignored) +static void igt_mm_align64(struct kunit *test) { - return igt_align_pot(64); + igt_align_pot(test, 64); } -static void show_scan(const struct drm_mm_scan *scan) +static void show_scan(struct kunit *test, const struct drm_mm_scan *scan) { - pr_info("scan: hit [%llx, %llx], size=%lld, align=%lld, color=%ld\n", - scan->hit_start, scan->hit_end, - scan->size, scan->alignment, scan->color); + kunit_info(test, "scan: hit [%llx, %llx], size=%lld, align=%lld, color=%ld\n", + scan->hit_start, scan->hit_end, scan->size, scan->alignment, scan->color); } -static void show_holes(const struct drm_mm *mm, int count) +static void show_holes(struct kunit *test, const struct drm_mm *mm, int count) { u64 hole_start, hole_end; struct drm_mm_node *hole; @@ -1274,19 +1159,15 @@ static void show_holes(const struct drm_mm *mm, int count) const char *node1 = NULL, *node2 = NULL; if (drm_mm_node_allocated(hole)) - node1 = kasprintf(GFP_KERNEL, - "[%llx + %lld, color=%ld], ", + node1 = kasprintf(GFP_KERNEL, "[%llx + %lld, color=%ld], ", hole->start, hole->size, hole->color); if (drm_mm_node_allocated(next)) - node2 = kasprintf(GFP_KERNEL, - ", [%llx + %lld, color=%ld]", + node2 = kasprintf(GFP_KERNEL, ", [%llx + %lld, color=%ld]", next->start, next->size, next->color); - pr_info("%sHole [%llx - %llx, size %lld]%s\n", - node1, - hole_start, hole_end, hole_end - hole_start, - node2); + kunit_info(test, "%sHole [%llx - %llx, size %lld]%s\n", node1, + hole_start, hole_end, hole_end - hole_start, node2); kfree(node2); kfree(node1); @@ -1301,12 +1182,9 @@ struct evict_node { struct list_head link; }; -static bool evict_nodes(struct drm_mm_scan *scan, - struct evict_node *nodes, - unsigned int *order, - unsigned int count, - bool use_color, - struct list_head *evict_list) +static bool evict_nodes(struct kunit *test, struct drm_mm_scan *scan, + struct evict_node *nodes, unsigned int *order, unsigned int count, + bool use_color, struct list_head *evict_list) { struct evict_node *e, *en; unsigned int i; @@ -1322,8 +1200,9 @@ static bool evict_nodes(struct drm_mm_scan *scan, list_del(&e->link); } if (list_empty(evict_list)) { - pr_err("Failed to find eviction: size=%lld [avail=%d], align=%lld (color=%lu)\n", - scan->size, count, scan->alignment, scan->color); + KUNIT_FAIL(test, + "Failed to find eviction: size=%lld [avail=%d], align=%lld (color=%lu)\n", + scan->size, count, scan->alignment, scan->color); return false; } @@ -1340,7 +1219,8 @@ static bool evict_nodes(struct drm_mm_scan *scan, } } else { if (drm_mm_scan_color_evict(scan)) { - pr_err("drm_mm_scan_color_evict unexpectedly reported overlapping nodes!\n"); + KUNIT_FAIL(test, + "drm_mm_scan_color_evict unexpectedly reported overlapping nodes!\n"); return false; } } @@ -1348,9 +1228,8 @@ static bool evict_nodes(struct drm_mm_scan *scan, return true; } -static bool evict_nothing(struct drm_mm *mm, - unsigned int total_size, - struct evict_node *nodes) +static bool evict_nothing(struct kunit *test, struct drm_mm *mm, + unsigned int total_size, struct evict_node *nodes) { struct drm_mm_scan scan; LIST_HEAD(evict_list); @@ -1371,7 +1250,7 @@ static bool evict_nothing(struct drm_mm *mm, e = &nodes[n]; if (!drm_mm_node_allocated(&e->node)) { - pr_err("node[%d] no longer allocated!\n", n); + KUNIT_FAIL(test, "node[%d] no longer allocated!\n", n); return false; } @@ -1387,17 +1266,16 @@ static bool evict_nothing(struct drm_mm *mm, e = &nodes[n]; if (!e->link.next) { - pr_err("node[%d] no longer connected!\n", n); + KUNIT_FAIL(test, "node[%d] no longer connected!\n", n); return false; } } - return assert_continuous(mm, nodes[0].node.size); + return assert_continuous(test, mm, nodes[0].node.size); } -static bool evict_everything(struct drm_mm *mm, - unsigned int total_size, - struct evict_node *nodes) +static bool evict_everything(struct kunit *test, struct drm_mm *mm, + unsigned int total_size, struct evict_node *nodes) { struct drm_mm_scan scan; LIST_HEAD(evict_list); @@ -1417,8 +1295,8 @@ static bool evict_everything(struct drm_mm *mm, list_for_each_entry(e, &evict_list, link) { if (!drm_mm_scan_remove_block(&scan, &e->node)) { if (!err) { - pr_err("Node %lld not marked for eviction!\n", - e->node.start); + KUNIT_FAIL(test, "Node %lld not marked for eviction!\n", + e->node.start); err = -EINVAL; } } @@ -1429,29 +1307,25 @@ static bool evict_everything(struct drm_mm *mm, list_for_each_entry(e, &evict_list, link) drm_mm_remove_node(&e->node); - if (!assert_one_hole(mm, 0, total_size)) + if (!assert_one_hole(test, mm, 0, total_size)) return false; list_for_each_entry(e, &evict_list, link) { err = drm_mm_reserve_node(mm, &e->node); if (err) { - pr_err("Failed to reinsert node after eviction: start=%llx\n", - e->node.start); + KUNIT_FAIL(test, "Failed to reinsert node after eviction: start=%llx\n", + e->node.start); return false; } } - return assert_continuous(mm, nodes[0].node.size); + return assert_continuous(test, mm, nodes[0].node.size); } -static int evict_something(struct drm_mm *mm, - u64 range_start, u64 range_end, - struct evict_node *nodes, - unsigned int *order, - unsigned int count, - unsigned int size, - unsigned int alignment, - const struct insert_mode *mode) +static int evict_something(struct kunit *test, struct drm_mm *mm, + u64 range_start, u64 range_end, struct evict_node *nodes, + unsigned int *order, unsigned int count, unsigned int size, + unsigned int alignment, const struct insert_mode *mode) { struct drm_mm_scan scan; LIST_HEAD(evict_list); @@ -1459,38 +1333,35 @@ static int evict_something(struct drm_mm *mm, struct drm_mm_node tmp; int err; - drm_mm_scan_init_with_range(&scan, mm, - size, alignment, 0, - range_start, range_end, - mode->mode); - if (!evict_nodes(&scan, - nodes, order, count, false, - &evict_list)) + drm_mm_scan_init_with_range(&scan, mm, size, alignment, 0, range_start, + range_end, mode->mode); + if (!evict_nodes(test, &scan, nodes, order, count, false, &evict_list)) return -EINVAL; memset(&tmp, 0, sizeof(tmp)); err = drm_mm_insert_node_generic(mm, &tmp, size, alignment, 0, DRM_MM_INSERT_EVICT); if (err) { - pr_err("Failed to insert into eviction hole: size=%d, align=%d\n", - size, alignment); - show_scan(&scan); - show_holes(mm, 3); + KUNIT_FAIL(test, "Failed to insert into eviction hole: size=%d, align=%d\n", + size, alignment); + show_scan(test, &scan); + show_holes(test, mm, 3); return err; } if (tmp.start < range_start || tmp.start + tmp.size > range_end) { - pr_err("Inserted [address=%llu + %llu] did not fit into the request range [%llu, %llu]\n", - tmp.start, tmp.size, range_start, range_end); + KUNIT_FAIL(test, + "Inserted [address=%llu + %llu] did not fit into the request range [%llu, %llu]\n", + tmp.start, tmp.size, range_start, range_end); err = -EINVAL; } - if (!assert_node(&tmp, mm, size, alignment, 0) || + if (!assert_node(test, &tmp, mm, size, alignment, 0) || drm_mm_hole_follows(&tmp)) { - pr_err("Inserted did not fill the eviction hole: size=%lld [%d], align=%d [rem=%lld], start=%llx, hole-follows?=%d\n", - tmp.size, size, - alignment, misalignment(&tmp, alignment), - tmp.start, drm_mm_hole_follows(&tmp)); + KUNIT_FAIL(test, + "Inserted did not fill the eviction hole: size=%lld [%d], align=%d [rem=%lld], start=%llx, hole-follows?=%d\n", + tmp.size, size, alignment, misalignment(&tmp, alignment), + tmp.start, drm_mm_hole_follows(&tmp)); err = -EINVAL; } @@ -1501,21 +1372,21 @@ static int evict_something(struct drm_mm *mm, list_for_each_entry(e, &evict_list, link) { err = drm_mm_reserve_node(mm, &e->node); if (err) { - pr_err("Failed to reinsert node after eviction: start=%llx\n", - e->node.start); + KUNIT_FAIL(test, "Failed to reinsert node after eviction: start=%llx\n", + e->node.start); return err; } } - if (!assert_continuous(mm, nodes[0].node.size)) { - pr_err("range is no longer continuous\n"); + if (!assert_continuous(test, mm, nodes[0].node.size)) { + KUNIT_FAIL(test, "range is no longer continuous\n"); return -EINVAL; } return 0; } -static int igt_evict(void *ignored) +static void igt_mm_evict(struct kunit *test) { DRM_RND_STATE(prng, random_seed); const unsigned int size = 8192; @@ -1524,7 +1395,6 @@ static int igt_evict(void *ignored) struct evict_node *nodes; struct drm_mm_node *node, *next; unsigned int *order, n; - int ret, err; /* Here we populate a full drm_mm and then try and insert a new node * by evicting other nodes in a random order. The drm_mm_scan should @@ -1533,61 +1403,49 @@ static int igt_evict(void *ignored) * sizes to try and stress the hole finder. */ - ret = -ENOMEM; nodes = vzalloc(array_size(size, sizeof(*nodes))); - if (!nodes) - goto err; + KUNIT_ASSERT_TRUE(test, nodes); order = drm_random_order(size, &prng); if (!order) goto err_nodes; - ret = -EINVAL; drm_mm_init(&mm, 0, size); for (n = 0; n < size; n++) { - err = drm_mm_insert_node(&mm, &nodes[n].node, 1); - if (err) { - pr_err("insert failed, step %d\n", n); - ret = err; + if (drm_mm_insert_node(&mm, &nodes[n].node, 1)) { + KUNIT_FAIL(test, "insert failed, step %d\n", n); goto out; } } /* First check that using the scanner doesn't break the mm */ - if (!evict_nothing(&mm, size, nodes)) { - pr_err("evict_nothing() failed\n"); + if (!evict_nothing(test, &mm, size, nodes)) { + KUNIT_FAIL(test, "evict_nothing() failed\n"); goto out; } - if (!evict_everything(&mm, size, nodes)) { - pr_err("evict_everything() failed\n"); + if (!evict_everything(test, &mm, size, nodes)) { + KUNIT_FAIL(test, "evict_everything() failed\n"); goto out; } for (mode = evict_modes; mode->name; mode++) { for (n = 1; n <= size; n <<= 1) { drm_random_reorder(order, size, &prng); - err = evict_something(&mm, 0, U64_MAX, - nodes, order, size, - n, 1, - mode); - if (err) { - pr_err("%s evict_something(size=%u) failed\n", - mode->name, n); - ret = err; + if (evict_something(test, &mm, 0, U64_MAX, nodes, order, size, n, 1, + mode)) { + KUNIT_FAIL(test, "%s evict_something(size=%u) failed\n", + mode->name, n); goto out; } } for (n = 1; n < size; n <<= 1) { drm_random_reorder(order, size, &prng); - err = evict_something(&mm, 0, U64_MAX, - nodes, order, size, - size/2, n, - mode); - if (err) { - pr_err("%s evict_something(size=%u, alignment=%u) failed\n", - mode->name, size/2, n); - ret = err; + if (evict_something(test, &mm, 0, U64_MAX, nodes, order, size, + size / 2, n, mode)) { + KUNIT_FAIL(test, + "%s evict_something(size=%u, alignment=%u) failed\n", + mode->name, size / 2, n); goto out; } } @@ -1598,14 +1456,11 @@ static int igt_evict(void *ignored) DRM_MM_BUG_ON(!nsize); drm_random_reorder(order, size, &prng); - err = evict_something(&mm, 0, U64_MAX, - nodes, order, size, - nsize, n, - mode); - if (err) { - pr_err("%s evict_something(size=%u, alignment=%u) failed\n", - mode->name, nsize, n); - ret = err; + if (evict_something(test, &mm, 0, U64_MAX, nodes, order, size, + nsize, n, mode)) { + KUNIT_FAIL(test, + "%s evict_something(size=%u, alignment=%u) failed\n", + mode->name, nsize, n); goto out; } } @@ -1613,7 +1468,6 @@ static int igt_evict(void *ignored) cond_resched(); } - ret = 0; out: drm_mm_for_each_node_safe(node, next, &mm) drm_mm_remove_node(node); @@ -1621,11 +1475,9 @@ out: kfree(order); err_nodes: vfree(nodes); -err: - return ret; } -static int igt_evict_range(void *ignored) +static void igt_mm_evict_range(struct kunit *test) { DRM_RND_STATE(prng, random_seed); const unsigned int size = 8192; @@ -1637,28 +1489,22 @@ static int igt_evict_range(void *ignored) struct evict_node *nodes; struct drm_mm_node *node, *next; unsigned int *order, n; - int ret, err; /* Like igt_evict() but now we are limiting the search to a * small portion of the full drm_mm. */ - ret = -ENOMEM; nodes = vzalloc(array_size(size, sizeof(*nodes))); - if (!nodes) - goto err; + KUNIT_ASSERT_TRUE(test, nodes); order = drm_random_order(size, &prng); if (!order) goto err_nodes; - ret = -EINVAL; drm_mm_init(&mm, 0, size); for (n = 0; n < size; n++) { - err = drm_mm_insert_node(&mm, &nodes[n].node, 1); - if (err) { - pr_err("insert failed, step %d\n", n); - ret = err; + if (drm_mm_insert_node(&mm, &nodes[n].node, 1)) { + KUNIT_FAIL(test, "insert failed, step %d\n", n); goto out; } } @@ -1666,26 +1512,22 @@ static int igt_evict_range(void *ignored) for (mode = evict_modes; mode->name; mode++) { for (n = 1; n <= range_size; n <<= 1) { drm_random_reorder(order, size, &prng); - err = evict_something(&mm, range_start, range_end, - nodes, order, size, - n, 1, - mode); - if (err) { - pr_err("%s evict_something(size=%u) failed with range [%u, %u]\n", - mode->name, n, range_start, range_end); + if (evict_something(test, &mm, range_start, range_end, nodes, + order, size, n, 1, mode)) { + KUNIT_FAIL(test, + "%s evict_something(size=%u) failed with range [%u, %u]\n", + mode->name, n, range_start, range_end); goto out; } } for (n = 1; n <= range_size; n <<= 1) { drm_random_reorder(order, size, &prng); - err = evict_something(&mm, range_start, range_end, - nodes, order, size, - range_size/2, n, - mode); - if (err) { - pr_err("%s evict_something(size=%u, alignment=%u) failed with range [%u, %u]\n", - mode->name, range_size/2, n, range_start, range_end); + if (evict_something(test, &mm, range_start, range_end, nodes, + order, size, range_size / 2, n, mode)) { + KUNIT_FAIL(test, + "%s evict_something(size=%u, alignment=%u) failed with range [%u, %u]\n", + mode->name, range_size / 2, n, range_start, range_end); goto out; } } @@ -1696,13 +1538,11 @@ static int igt_evict_range(void *ignored) DRM_MM_BUG_ON(!nsize); drm_random_reorder(order, size, &prng); - err = evict_something(&mm, range_start, range_end, - nodes, order, size, - nsize, n, - mode); - if (err) { - pr_err("%s evict_something(size=%u, alignment=%u) failed with range [%u, %u]\n", - mode->name, nsize, n, range_start, range_end); + if (evict_something(test, &mm, range_start, range_end, nodes, + order, size, nsize, n, mode)) { + KUNIT_FAIL(test, + "%s evict_something(size=%u, alignment=%u) failed with range [%u, %u]\n", + mode->name, nsize, n, range_start, range_end); goto out; } } @@ -1710,7 +1550,6 @@ static int igt_evict_range(void *ignored) cond_resched(); } - ret = 0; out: drm_mm_for_each_node_safe(node, next, &mm) drm_mm_remove_node(node); @@ -1718,8 +1557,6 @@ out: kfree(order); err_nodes: vfree(nodes); -err: - return ret; } static unsigned int node_index(const struct drm_mm_node *node) @@ -1727,9 +1564,10 @@ static unsigned int node_index(const struct drm_mm_node *node) return div64_u64(node->start, node->size); } -static int igt_topdown(void *ignored) +static void igt_mm_topdown(struct kunit *test) { const struct insert_mode *topdown = &insert_modes[TOPDOWN]; + DRM_RND_STATE(prng, random_seed); const unsigned int count = 8192; unsigned int size; @@ -1737,17 +1575,14 @@ static int igt_topdown(void *ignored) struct drm_mm mm; struct drm_mm_node *nodes, *node, *next; unsigned int *order, n, m, o = 0; - int ret; /* When allocating top-down, we expect to be returned a node * from a suitable hole at the top of the drm_mm. We check that * the returned node does match the highest available slot. */ - ret = -ENOMEM; nodes = vzalloc(array_size(count, sizeof(*nodes))); - if (!nodes) - goto err; + KUNIT_ASSERT_TRUE(test, nodes); bitmap = bitmap_zalloc(count, GFP_KERNEL); if (!bitmap) @@ -1757,28 +1592,26 @@ static int igt_topdown(void *ignored) if (!order) goto err_bitmap; - ret = -EINVAL; for (size = 1; size <= 64; size <<= 1) { - drm_mm_init(&mm, 0, size*count); + drm_mm_init(&mm, 0, size * count); for (n = 0; n < count; n++) { - if (!expect_insert(&mm, &nodes[n], - size, 0, n, - topdown)) { - pr_err("insert failed, size %u step %d\n", size, n); + if (!expect_insert(test, &mm, &nodes[n], size, 0, n, topdown)) { + KUNIT_FAIL(test, "insert failed, size %u step %d\n", size, n); goto out; } if (drm_mm_hole_follows(&nodes[n])) { - pr_err("hole after topdown insert %d, start=%llx\n, size=%u", - n, nodes[n].start, size); + KUNIT_FAIL(test, + "hole after topdown insert %d, start=%llx\n, size=%u", + n, nodes[n].start, size); goto out; } - if (!assert_one_hole(&mm, 0, size*(count - n - 1))) + if (!assert_one_hole(test, &mm, 0, size * (count - n - 1))) goto out; } - if (!assert_continuous(&mm, size)) + if (!assert_continuous(test, &mm, size)) goto out; drm_random_reorder(order, count, &prng); @@ -1793,23 +1626,23 @@ static int igt_topdown(void *ignored) unsigned int last; node = &nodes[order[(o + m) % count]]; - if (!expect_insert(&mm, node, - size, 0, 0, - topdown)) { - pr_err("insert failed, step %d/%d\n", m, n); + if (!expect_insert(test, &mm, node, size, 0, 0, topdown)) { + KUNIT_FAIL(test, "insert failed, step %d/%d\n", m, n); goto out; } if (drm_mm_hole_follows(node)) { - pr_err("hole after topdown insert %d/%d, start=%llx\n", - m, n, node->start); + KUNIT_FAIL(test, + "hole after topdown insert %d/%d, start=%llx\n", + m, n, node->start); goto out; } last = find_last_bit(bitmap, count); if (node_index(node) != last) { - pr_err("node %d/%d, size %d, not inserted into upmost hole, expected %d, found %d\n", - m, n, size, last, node_index(node)); + KUNIT_FAIL(test, + "node %d/%d, size %d, not inserted into upmost hole, expected %d, found %d\n", + m, n, size, last, node_index(node)); goto out; } @@ -1827,7 +1660,6 @@ static int igt_topdown(void *ignored) cond_resched(); } - ret = 0; out: drm_mm_for_each_node_safe(node, next, &mm) drm_mm_remove_node(node); @@ -1837,13 +1669,12 @@ err_bitmap: bitmap_free(bitmap); err_nodes: vfree(nodes); -err: - return ret; } -static int igt_bottomup(void *ignored) +static void igt_mm_bottomup(struct kunit *test) { const struct insert_mode *bottomup = &insert_modes[BOTTOMUP]; + DRM_RND_STATE(prng, random_seed); const unsigned int count = 8192; unsigned int size; @@ -1851,16 +1682,13 @@ static int igt_bottomup(void *ignored) struct drm_mm mm; struct drm_mm_node *nodes, *node, *next; unsigned int *order, n, m, o = 0; - int ret; /* Like igt_topdown, but instead of searching for the last hole, * we search for the first. */ - ret = -ENOMEM; nodes = vzalloc(array_size(count, sizeof(*nodes))); - if (!nodes) - goto err; + KUNIT_ASSERT_TRUE(test, nodes); bitmap = bitmap_zalloc(count, GFP_KERNEL); if (!bitmap) @@ -1870,22 +1698,20 @@ static int igt_bottomup(void *ignored) if (!order) goto err_bitmap; - ret = -EINVAL; for (size = 1; size <= 64; size <<= 1) { - drm_mm_init(&mm, 0, size*count); + drm_mm_init(&mm, 0, size * count); for (n = 0; n < count; n++) { - if (!expect_insert(&mm, &nodes[n], - size, 0, n, - bottomup)) { - pr_err("bottomup insert failed, size %u step %d\n", size, n); + if (!expect_insert(test, &mm, &nodes[n], size, 0, n, bottomup)) { + KUNIT_FAIL(test, + "bottomup insert failed, size %u step %d\n", size, n); goto out; } - if (!assert_one_hole(&mm, size*(n + 1), size*count)) + if (!assert_one_hole(test, &mm, size * (n + 1), size * count)) goto out; } - if (!assert_continuous(&mm, size)) + if (!assert_continuous(test, &mm, size)) goto out; drm_random_reorder(order, count, &prng); @@ -1900,17 +1726,16 @@ static int igt_bottomup(void *ignored) unsigned int first; node = &nodes[order[(o + m) % count]]; - if (!expect_insert(&mm, node, - size, 0, 0, - bottomup)) { - pr_err("insert failed, step %d/%d\n", m, n); + if (!expect_insert(test, &mm, node, size, 0, 0, bottomup)) { + KUNIT_FAIL(test, "insert failed, step %d/%d\n", m, n); goto out; } first = find_first_bit(bitmap, count); if (node_index(node) != first) { - pr_err("node %d/%d not inserted into bottom hole, expected %d, found %d\n", - m, n, first, node_index(node)); + KUNIT_FAIL(test, + "node %d/%d not inserted into bottom hole, expected %d, found %d\n", + m, n, first, node_index(node)); goto out; } __clear_bit(first, bitmap); @@ -1927,7 +1752,6 @@ static int igt_bottomup(void *ignored) cond_resched(); } - ret = 0; out: drm_mm_for_each_node_safe(node, next, &mm) drm_mm_remove_node(node); @@ -1937,47 +1761,39 @@ err_bitmap: bitmap_free(bitmap); err_nodes: vfree(nodes); -err: - return ret; } -static int __igt_once(unsigned int mode) +static void __igt_once(struct kunit *test, unsigned int mode) { struct drm_mm mm; struct drm_mm_node rsvd_lo, rsvd_hi, node; - int err; drm_mm_init(&mm, 0, 7); memset(&rsvd_lo, 0, sizeof(rsvd_lo)); rsvd_lo.start = 1; rsvd_lo.size = 1; - err = drm_mm_reserve_node(&mm, &rsvd_lo); - if (err) { - pr_err("Could not reserve low node\n"); + if (drm_mm_reserve_node(&mm, &rsvd_lo)) { + KUNIT_FAIL(test, "Could not reserve low node\n"); goto err; } memset(&rsvd_hi, 0, sizeof(rsvd_hi)); rsvd_hi.start = 5; rsvd_hi.size = 1; - err = drm_mm_reserve_node(&mm, &rsvd_hi); - if (err) { - pr_err("Could not reserve low node\n"); + if (drm_mm_reserve_node(&mm, &rsvd_hi)) { + KUNIT_FAIL(test, "Could not reserve low node\n"); goto err_lo; } if (!drm_mm_hole_follows(&rsvd_lo) || !drm_mm_hole_follows(&rsvd_hi)) { - pr_err("Expected a hole after lo and high nodes!\n"); - err = -EINVAL; + KUNIT_FAIL(test, "Expected a hole after lo and high nodes!\n"); goto err_hi; } memset(&node, 0, sizeof(node)); - err = drm_mm_insert_node_generic(&mm, &node, 2, 0, 0, mode); - if (err) { - pr_err("Could not insert the node into the available hole!\n"); - err = -EINVAL; + if (drm_mm_insert_node_generic(&mm, &node, 2, 0, 0, mode)) { + KUNIT_FAIL(test, "Could not insert the node into the available hole!\n"); goto err_hi; } @@ -1988,23 +1804,20 @@ err_lo: drm_mm_remove_node(&rsvd_lo); err: drm_mm_takedown(&mm); - return err; } -static int igt_lowest(void *ignored) +static void igt_mm_lowest(struct kunit *test) { - return __igt_once(DRM_MM_INSERT_LOW); + __igt_once(test, DRM_MM_INSERT_LOW); } -static int igt_highest(void *ignored) +static void igt_mm_highest(struct kunit *test) { - return __igt_once(DRM_MM_INSERT_HIGH); + __igt_once(test, DRM_MM_INSERT_HIGH); } static void separate_adjacent_colors(const struct drm_mm_node *node, - unsigned long color, - u64 *start, - u64 *end) + unsigned long color, u64 *start, u64 *end) { if (drm_mm_node_allocated(node) && node->color != color) ++*start; @@ -2014,12 +1827,12 @@ static void separate_adjacent_colors(const struct drm_mm_node *node, --*end; } -static bool colors_abutt(const struct drm_mm_node *node) +static bool colors_abutt(struct kunit *test, const struct drm_mm_node *node) { if (!drm_mm_hole_follows(node) && drm_mm_node_allocated(list_next_entry(node, node_list))) { - pr_err("colors abutt; %ld [%llx + %llx] is next to %ld [%llx + %llx]!\n", - node->color, node->start, node->size, + KUNIT_FAIL(test, "colors abutt; %ld [%llx + %llx] is next to %ld [%llx + %llx]!\n", + node->color, node->start, node->size, list_next_entry(node, node_list)->color, list_next_entry(node, node_list)->start, list_next_entry(node, node_list)->size); @@ -2029,14 +1842,13 @@ static bool colors_abutt(const struct drm_mm_node *node) return false; } -static int igt_color(void *ignored) +static void igt_mm_color(struct kunit *test) { const unsigned int count = min(4096u, max_iterations); const struct insert_mode *mode; struct drm_mm mm; struct drm_mm_node *node, *nn; unsigned int n; - int ret = -EINVAL, err; /* Color adjustment complicates everything. First we just check * that when we insert a node we apply any color_adjustment callback. @@ -2049,15 +1861,11 @@ static int igt_color(void *ignored) for (n = 1; n <= count; n++) { node = kzalloc(sizeof(*node), GFP_KERNEL); - if (!node) { - ret = -ENOMEM; + if (!node) goto out; - } - if (!expect_insert(&mm, node, - n, 0, n, - &insert_modes[0])) { - pr_err("insert failed, step %d\n", n); + if (!expect_insert(test, &mm, node, n, 0, n, &insert_modes[0])) { + KUNIT_FAIL(test, "insert failed, step %d\n", n); kfree(node); goto out; } @@ -2065,8 +1873,8 @@ static int igt_color(void *ignored) drm_mm_for_each_node_safe(node, nn, &mm) { if (node->color != node->size) { - pr_err("invalid color stored: expected %lld, found %ld\n", - node->size, node->color); + KUNIT_FAIL(test, "invalid color stored: expected %lld, found %ld\n", + node->size, node->color); goto out; } @@ -2081,18 +1889,14 @@ static int igt_color(void *ignored) u64 last; node = kzalloc(sizeof(*node), GFP_KERNEL); - if (!node) { - ret = -ENOMEM; + if (!node) goto out; - } - node->size = 1 + 2*count; + node->size = 1 + 2 * count; node->color = node->size; - err = drm_mm_reserve_node(&mm, node); - if (err) { - pr_err("initial reserve failed!\n"); - ret = err; + if (drm_mm_reserve_node(&mm, node)) { + KUNIT_FAIL(test, "initial reserve failed!\n"); goto out; } @@ -2102,19 +1906,15 @@ static int igt_color(void *ignored) int rem; node = kzalloc(sizeof(*node), GFP_KERNEL); - if (!node) { - ret = -ENOMEM; + if (!node) goto out; - } node->start = last; node->size = n + count; node->color = node->size; - err = drm_mm_reserve_node(&mm, node); - if (err != -ENOSPC) { - pr_err("reserve %d did not report color overlap! err=%d\n", - n, err); + if (drm_mm_reserve_node(&mm, node) != -ENOSPC) { + KUNIT_FAIL(test, "reserve %d did not report color overlap!", n); goto out; } @@ -2122,10 +1922,8 @@ static int igt_color(void *ignored) rem = misalignment(node, n + count); node->start += n + count - rem; - err = drm_mm_reserve_node(&mm, node); - if (err) { - pr_err("reserve %d failed, err=%d\n", n, err); - ret = err; + if (drm_mm_reserve_node(&mm, node)) { + KUNIT_FAIL(test, "reserve %d failed", n); goto out; } @@ -2134,16 +1932,11 @@ static int igt_color(void *ignored) for (n = 1; n <= count; n++) { node = kzalloc(sizeof(*node), GFP_KERNEL); - if (!node) { - ret = -ENOMEM; + if (!node) goto out; - } - if (!expect_insert(&mm, node, - n, n, n, - mode)) { - pr_err("%s insert failed, step %d\n", - mode->name, n); + if (!expect_insert(test, &mm, node, n, n, n, mode)) { + KUNIT_FAIL(test, "%s insert failed, step %d\n", mode->name, n); kfree(node); goto out; } @@ -2153,19 +1946,21 @@ static int igt_color(void *ignored) u64 rem; if (node->color != node->size) { - pr_err("%s invalid color stored: expected %lld, found %ld\n", - mode->name, node->size, node->color); + KUNIT_FAIL(test, + "%s invalid color stored: expected %lld, found %ld\n", + mode->name, node->size, node->color); goto out; } - if (colors_abutt(node)) + if (colors_abutt(test, node)) goto out; div64_u64_rem(node->start, node->size, &rem); if (rem) { - pr_err("%s colored node misaligned, start=%llx expected alignment=%lld [rem=%lld]\n", - mode->name, node->start, node->size, rem); + KUNIT_FAIL(test, + "%s colored node misaligned, start=%llx expected alignment=%lld [rem=%lld]\n", + mode->name, node->start, node->size, rem); goto out; } @@ -2176,25 +1971,18 @@ static int igt_color(void *ignored) cond_resched(); } - ret = 0; out: drm_mm_for_each_node_safe(node, nn, &mm) { drm_mm_remove_node(node); kfree(node); } drm_mm_takedown(&mm); - return ret; } -static int evict_color(struct drm_mm *mm, - u64 range_start, u64 range_end, - struct evict_node *nodes, - unsigned int *order, - unsigned int count, - unsigned int size, - unsigned int alignment, - unsigned long color, - const struct insert_mode *mode) +static int evict_color(struct kunit *test, struct drm_mm *mm, u64 range_start, + u64 range_end, struct evict_node *nodes, unsigned int *order, + unsigned int count, unsigned int size, unsigned int alignment, + unsigned long color, const struct insert_mode *mode) { struct drm_mm_scan scan; LIST_HEAD(evict_list); @@ -2202,39 +1990,37 @@ static int evict_color(struct drm_mm *mm, struct drm_mm_node tmp; int err; - drm_mm_scan_init_with_range(&scan, mm, - size, alignment, color, - range_start, range_end, - mode->mode); - if (!evict_nodes(&scan, - nodes, order, count, true, - &evict_list)) + drm_mm_scan_init_with_range(&scan, mm, size, alignment, color, range_start, + range_end, mode->mode); + if (!evict_nodes(test, &scan, nodes, order, count, true, &evict_list)) return -EINVAL; memset(&tmp, 0, sizeof(tmp)); err = drm_mm_insert_node_generic(mm, &tmp, size, alignment, color, DRM_MM_INSERT_EVICT); if (err) { - pr_err("Failed to insert into eviction hole: size=%d, align=%d, color=%lu, err=%d\n", - size, alignment, color, err); - show_scan(&scan); - show_holes(mm, 3); + KUNIT_FAIL(test, + "Failed to insert into eviction hole: size=%d, align=%d, color=%lu, err=%d\n", + size, alignment, color, err); + show_scan(test, &scan); + show_holes(test, mm, 3); return err; } if (tmp.start < range_start || tmp.start + tmp.size > range_end) { - pr_err("Inserted [address=%llu + %llu] did not fit into the request range [%llu, %llu]\n", - tmp.start, tmp.size, range_start, range_end); + KUNIT_FAIL(test, + "Inserted [address=%llu + %llu] did not fit into the request range [%llu, %llu]\n", + tmp.start, tmp.size, range_start, range_end); err = -EINVAL; } - if (colors_abutt(&tmp)) + if (colors_abutt(test, &tmp)) err = -EINVAL; - if (!assert_node(&tmp, mm, size, alignment, color)) { - pr_err("Inserted did not fit the eviction hole: size=%lld [%d], align=%d [rem=%lld], start=%llx\n", - tmp.size, size, - alignment, misalignment(&tmp, alignment), tmp.start); + if (!assert_node(test, &tmp, mm, size, alignment, color)) { + KUNIT_FAIL(test, + "Inserted did not fit the eviction hole: size=%lld [%d], align=%d [rem=%lld], start=%llx\n", + tmp.size, size, alignment, misalignment(&tmp, alignment), tmp.start); err = -EINVAL; } @@ -2245,8 +2031,8 @@ static int evict_color(struct drm_mm *mm, list_for_each_entry(e, &evict_list, link) { err = drm_mm_reserve_node(mm, &e->node); if (err) { - pr_err("Failed to reinsert node after eviction: start=%llx\n", - e->node.start); + KUNIT_FAIL(test, "Failed to reinsert node after eviction: start=%llx\n", + e->node.start); return err; } } @@ -2255,7 +2041,7 @@ static int evict_color(struct drm_mm *mm, return 0; } -static int igt_color_evict(void *ignored) +static void igt_mm_color_evict(struct kunit *test) { DRM_RND_STATE(prng, random_seed); const unsigned int total_size = min(8192u, max_iterations); @@ -2265,7 +2051,6 @@ static int igt_color_evict(void *ignored) struct evict_node *nodes; struct drm_mm_node *node, *next; unsigned int *order, n; - int ret, err; /* Check that the drm_mm_scan also honours color adjustment when * choosing its victims to create a hole. Our color_adjust does not @@ -2273,23 +2058,20 @@ static int igt_color_evict(void *ignored) * enlarging the set of victims that must be evicted. */ - ret = -ENOMEM; nodes = vzalloc(array_size(total_size, sizeof(*nodes))); - if (!nodes) - goto err; + KUNIT_ASSERT_TRUE(test, nodes); order = drm_random_order(total_size, &prng); if (!order) goto err_nodes; - ret = -EINVAL; - drm_mm_init(&mm, 0, 2*total_size - 1); + drm_mm_init(&mm, 0, 2 * total_size - 1); mm.color_adjust = separate_adjacent_colors; for (n = 0; n < total_size; n++) { - if (!expect_insert(&mm, &nodes[n].node, + if (!expect_insert(test, &mm, &nodes[n].node, 1, 0, color++, &insert_modes[0])) { - pr_err("insert failed, step %d\n", n); + KUNIT_FAIL(test, "insert failed, step %d\n", n); goto out; } } @@ -2297,26 +2079,19 @@ static int igt_color_evict(void *ignored) for (mode = evict_modes; mode->name; mode++) { for (n = 1; n <= total_size; n <<= 1) { drm_random_reorder(order, total_size, &prng); - err = evict_color(&mm, 0, U64_MAX, - nodes, order, total_size, - n, 1, color++, - mode); - if (err) { - pr_err("%s evict_color(size=%u) failed\n", - mode->name, n); + if (evict_color(test, &mm, 0, U64_MAX, nodes, order, total_size, + n, 1, color++, mode)) { + KUNIT_FAIL(test, "%s evict_color(size=%u) failed\n", mode->name, n); goto out; } } for (n = 1; n < total_size; n <<= 1) { drm_random_reorder(order, total_size, &prng); - err = evict_color(&mm, 0, U64_MAX, - nodes, order, total_size, - total_size/2, n, color++, - mode); - if (err) { - pr_err("%s evict_color(size=%u, alignment=%u) failed\n", - mode->name, total_size/2, n); + if (evict_color(test, &mm, 0, U64_MAX, nodes, order, total_size, + total_size / 2, n, color++, mode)) { + KUNIT_FAIL(test, "%s evict_color(size=%u, alignment=%u) failed\n", + mode->name, total_size / 2, n); goto out; } } @@ -2327,13 +2102,10 @@ static int igt_color_evict(void *ignored) DRM_MM_BUG_ON(!nsize); drm_random_reorder(order, total_size, &prng); - err = evict_color(&mm, 0, U64_MAX, - nodes, order, total_size, - nsize, n, color++, - mode); - if (err) { - pr_err("%s evict_color(size=%u, alignment=%u) failed\n", - mode->name, nsize, n); + if (evict_color(test, &mm, 0, U64_MAX, nodes, order, total_size, + nsize, n, color++, mode)) { + KUNIT_FAIL(test, "%s evict_color(size=%u, alignment=%u) failed\n", + mode->name, nsize, n); goto out; } } @@ -2341,21 +2113,16 @@ static int igt_color_evict(void *ignored) cond_resched(); } - ret = 0; out: - if (ret) - show_mm(&mm); drm_mm_for_each_node_safe(node, next, &mm) drm_mm_remove_node(node); drm_mm_takedown(&mm); kfree(order); err_nodes: vfree(nodes); -err: - return ret; } -static int igt_color_evict_range(void *ignored) +static void igt_mm_color_evict_range(struct kunit *test) { DRM_RND_STATE(prng, random_seed); const unsigned int total_size = 8192; @@ -2368,29 +2135,25 @@ static int igt_color_evict_range(void *ignored) struct evict_node *nodes; struct drm_mm_node *node, *next; unsigned int *order, n; - int ret, err; /* Like igt_color_evict(), but limited to small portion of the full * drm_mm range. */ - ret = -ENOMEM; nodes = vzalloc(array_size(total_size, sizeof(*nodes))); - if (!nodes) - goto err; + KUNIT_ASSERT_TRUE(test, nodes); order = drm_random_order(total_size, &prng); if (!order) goto err_nodes; - ret = -EINVAL; - drm_mm_init(&mm, 0, 2*total_size - 1); + drm_mm_init(&mm, 0, 2 * total_size - 1); mm.color_adjust = separate_adjacent_colors; for (n = 0; n < total_size; n++) { - if (!expect_insert(&mm, &nodes[n].node, + if (!expect_insert(test, &mm, &nodes[n].node, 1, 0, color++, &insert_modes[0])) { - pr_err("insert failed, step %d\n", n); + KUNIT_FAIL(test, "insert failed, step %d\n", n); goto out; } } @@ -2398,26 +2161,22 @@ static int igt_color_evict_range(void *ignored) for (mode = evict_modes; mode->name; mode++) { for (n = 1; n <= range_size; n <<= 1) { drm_random_reorder(order, range_size, &prng); - err = evict_color(&mm, range_start, range_end, - nodes, order, total_size, - n, 1, color++, - mode); - if (err) { - pr_err("%s evict_color(size=%u) failed for range [%x, %x]\n", - mode->name, n, range_start, range_end); + if (evict_color(test, &mm, range_start, range_end, nodes, order, + total_size, n, 1, color++, mode)) { + KUNIT_FAIL(test, + "%s evict_color(size=%u) failed for range [%x, %x]\n", + mode->name, n, range_start, range_end); goto out; } } for (n = 1; n < range_size; n <<= 1) { drm_random_reorder(order, total_size, &prng); - err = evict_color(&mm, range_start, range_end, - nodes, order, total_size, - range_size/2, n, color++, - mode); - if (err) { - pr_err("%s evict_color(size=%u, alignment=%u) failed for range [%x, %x]\n", - mode->name, total_size/2, n, range_start, range_end); + if (evict_color(test, &mm, range_start, range_end, nodes, order, + total_size, range_size / 2, n, color++, mode)) { + KUNIT_FAIL(test, + "%s evict_color(size=%u, alignment=%u) failed for range [%x, %x]\n", + mode->name, total_size / 2, n, range_start, range_end); goto out; } } @@ -2428,13 +2187,11 @@ static int igt_color_evict_range(void *ignored) DRM_MM_BUG_ON(!nsize); drm_random_reorder(order, total_size, &prng); - err = evict_color(&mm, range_start, range_end, - nodes, order, total_size, - nsize, n, color++, - mode); - if (err) { - pr_err("%s evict_color(size=%u, alignment=%u) failed for range [%x, %x]\n", - mode->name, nsize, n, range_start, range_end); + if (evict_color(test, &mm, range_start, range_end, nodes, order, + total_size, nsize, n, color++, mode)) { + KUNIT_FAIL(test, + "%s evict_color(size=%u, alignment=%u) failed for range [%x, %x]\n", + mode->name, nsize, n, range_start, range_end); goto out; } } @@ -2442,46 +2199,57 @@ static int igt_color_evict_range(void *ignored) cond_resched(); } - ret = 0; out: - if (ret) - show_mm(&mm); drm_mm_for_each_node_safe(node, next, &mm) drm_mm_remove_node(node); drm_mm_takedown(&mm); kfree(order); err_nodes: vfree(nodes); -err: - return ret; } -#include "drm_selftest.c" - -static int __init test_drm_mm_init(void) +static int drm_mm_init_test(struct kunit *test) { - int err; - while (!random_seed) random_seed = get_random_int(); - pr_info("Testing DRM range manager (struct drm_mm), with random_seed=0x%x max_iterations=%u max_prime=%u\n", - random_seed, max_iterations, max_prime); - err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL); - - return err > 0 ? 0 : err; -} - -static void __exit test_drm_mm_exit(void) -{ + return 0; } -module_init(test_drm_mm_init); -module_exit(test_drm_mm_exit); - module_param(random_seed, uint, 0400); module_param(max_iterations, uint, 0400); module_param(max_prime, uint, 0400); +static struct kunit_case drm_mm_tests[] = { + KUNIT_CASE(igt_mm_init), + KUNIT_CASE(igt_mm_debug), + KUNIT_CASE(igt_mm_reserve), + KUNIT_CASE(igt_mm_insert), + KUNIT_CASE(igt_mm_replace), + KUNIT_CASE(igt_mm_insert_range), + KUNIT_CASE(igt_mm_frag), + KUNIT_CASE(igt_mm_align), + KUNIT_CASE(igt_mm_align32), + KUNIT_CASE(igt_mm_align64), + KUNIT_CASE(igt_mm_evict), + KUNIT_CASE(igt_mm_evict_range), + KUNIT_CASE(igt_mm_topdown), + KUNIT_CASE(igt_mm_bottomup), + KUNIT_CASE(igt_mm_lowest), + KUNIT_CASE(igt_mm_highest), + KUNIT_CASE(igt_mm_color), + KUNIT_CASE(igt_mm_color_evict), + KUNIT_CASE(igt_mm_color_evict_range), + {} +}; + +static struct kunit_suite drm_mm_test_suite = { + .name = "drm_mm", + .init = drm_mm_init_test, + .test_cases = drm_mm_tests, +}; + +kunit_test_suite(drm_mm_test_suite); + MODULE_AUTHOR("Intel Corporation"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/selftests/test-drm_plane_helper.c b/drivers/gpu/drm/tests/drm_plane_helper_test.c index 64e8938ab194..be6cff0020ed 100644 --- a/drivers/gpu/drm/selftests/test-drm_plane_helper.c +++ b/drivers/gpu/drm/tests/drm_plane_helper_test.c @@ -1,20 +1,19 @@ // SPDX-License-Identifier: GPL-2.0 /* * Test cases for the drm_plane_helper functions + * + * Copyright (c) 2022 MaÃra Canal <mairacanal@riseup.net> */ -#define pr_fmt(fmt) "drm_plane_helper: " fmt +#include <kunit/test.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_modes.h> -#include "test-drm_modeset_common.h" - static void set_src(struct drm_plane_state *plane_state, - unsigned src_x, unsigned src_y, - unsigned src_w, unsigned src_h) + unsigned int src_x, unsigned int src_y, + unsigned int src_w, unsigned int src_h) { plane_state->src_x = src_x; plane_state->src_y = src_y; @@ -23,8 +22,8 @@ static void set_src(struct drm_plane_state *plane_state, } static bool check_src_eq(struct drm_plane_state *plane_state, - unsigned src_x, unsigned src_y, - unsigned src_w, unsigned src_h) + unsigned int src_x, unsigned int src_y, + unsigned int src_w, unsigned int src_h) { if (plane_state->src.x1 < 0) { pr_err("src x coordinate %x should never be below 0.\n", plane_state->src.x1); @@ -50,7 +49,7 @@ static bool check_src_eq(struct drm_plane_state *plane_state, static void set_crtc(struct drm_plane_state *plane_state, int crtc_x, int crtc_y, - unsigned crtc_w, unsigned crtc_h) + unsigned int crtc_w, unsigned int crtc_h) { plane_state->crtc_x = crtc_x; plane_state->crtc_y = crtc_y; @@ -60,7 +59,7 @@ static void set_crtc(struct drm_plane_state *plane_state, static bool check_crtc_eq(struct drm_plane_state *plane_state, int crtc_x, int crtc_y, - unsigned crtc_w, unsigned crtc_h) + unsigned int crtc_w, unsigned int crtc_h) { if (plane_state->dst.x1 != crtc_x || plane_state->dst.y1 != crtc_y || @@ -74,7 +73,7 @@ static bool check_crtc_eq(struct drm_plane_state *plane_state, return true; } -int igt_check_plane_state(void *ignored) +static void igt_check_plane_state(struct kunit *test) { int ret; @@ -83,9 +82,8 @@ int igt_check_plane_state(void *ignored) .enable = true, .active = true, .mode = { - DRM_MODE("1024x768", 0, 65000, 1024, 1048, - 1184, 1344, 0, 768, 771, 777, 806, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) + DRM_MODE("1024x768", 0, 65000, 1024, 1048, 1184, 1344, 0, 768, 771, + 777, 806, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, }; static struct drm_plane plane = { @@ -106,119 +104,134 @@ int igt_check_plane_state(void *ignored) set_src(&plane_state, 0, 0, fb.width << 16, fb.height << 16); set_crtc(&plane_state, 0, 0, fb.width, fb.height); ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, false, false); - FAIL(ret < 0, "Simple clipping check should pass\n"); - FAIL_ON(!plane_state.visible); - FAIL_ON(!check_src_eq(&plane_state, 0, 0, 1024 << 16, 768 << 16)); - FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768)); + KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Simple clipping check should pass\n"); + KUNIT_EXPECT_TRUE(test, plane_state.visible); + KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 1024 << 16, 768 << 16)); + KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); /* Rotated clipping + reflection, no scaling. */ plane_state.rotation = DRM_MODE_ROTATE_90 | DRM_MODE_REFLECT_X; ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, false, false); - FAIL(ret < 0, "Rotated clipping check should pass\n"); - FAIL_ON(!plane_state.visible); - FAIL_ON(!check_src_eq(&plane_state, 0, 0, 768 << 16, 1024 << 16)); - FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768)); + KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Rotated clipping check should pass\n"); + KUNIT_EXPECT_TRUE(test, plane_state.visible); + KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 768 << 16, 1024 << 16)); + KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); plane_state.rotation = DRM_MODE_ROTATE_0; /* Check whether positioning works correctly. */ set_src(&plane_state, 0, 0, 1023 << 16, 767 << 16); set_crtc(&plane_state, 0, 0, 1023, 767); ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, false, false); - FAIL(!ret, "Should not be able to position on the crtc with can_position=false\n"); + KUNIT_EXPECT_TRUE_MSG(test, ret, + "Should not be able to position on the crtc with can_position=false\n"); ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, true, false); - FAIL(ret < 0, "Simple positioning should work\n"); - FAIL_ON(!plane_state.visible); - FAIL_ON(!check_src_eq(&plane_state, 0, 0, 1023 << 16, 767 << 16)); - FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1023, 767)); + KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Simple positioning should work\n"); + KUNIT_EXPECT_TRUE(test, plane_state.visible); + KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 1023 << 16, 767 << 16)); + KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1023, 767)); /* Simple scaling tests. */ set_src(&plane_state, 0, 0, 512 << 16, 384 << 16); set_crtc(&plane_state, 0, 0, 1024, 768); ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 0x8001, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, false, false); - FAIL(!ret, "Upscaling out of range should fail.\n"); + KUNIT_EXPECT_TRUE_MSG(test, ret, "Upscaling out of range should fail.\n"); ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 0x8000, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, false, false); - FAIL(ret < 0, "Upscaling exactly 2x should work\n"); - FAIL_ON(!plane_state.visible); - FAIL_ON(!check_src_eq(&plane_state, 0, 0, 512 << 16, 384 << 16)); - FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768)); + KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Upscaling exactly 2x should work\n"); + KUNIT_EXPECT_TRUE(test, plane_state.visible); + KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 512 << 16, 384 << 16)); + KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); set_src(&plane_state, 0, 0, 2048 << 16, 1536 << 16); ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, 0x1ffff, false, false); - FAIL(!ret, "Downscaling out of range should fail.\n"); + KUNIT_EXPECT_TRUE_MSG(test, ret, "Downscaling out of range should fail.\n"); ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, 0x20000, false, false); - FAIL(ret < 0, "Should succeed with exact scaling limit\n"); - FAIL_ON(!plane_state.visible); - FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2048 << 16, 1536 << 16)); - FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768)); + KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed with exact scaling limit\n"); + KUNIT_EXPECT_TRUE(test, plane_state.visible); + KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 2048 << 16, 1536 << 16)); + KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); /* Testing rounding errors. */ set_src(&plane_state, 0, 0, 0x40001, 0x40001); set_crtc(&plane_state, 1022, 766, 4, 4); ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, 0x10001, true, false); - FAIL(ret < 0, "Should succeed by clipping to exact multiple"); - FAIL_ON(!plane_state.visible); - FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16)); - FAIL_ON(!check_crtc_eq(&plane_state, 1022, 766, 2, 2)); + KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple"); + KUNIT_EXPECT_TRUE(test, plane_state.visible); + KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16)); + KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 1022, 766, 2, 2)); set_src(&plane_state, 0x20001, 0x20001, 0x4040001, 0x3040001); set_crtc(&plane_state, -2, -2, 1028, 772); ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, 0x10001, false, false); - FAIL(ret < 0, "Should succeed by clipping to exact multiple"); - FAIL_ON(!plane_state.visible); - FAIL_ON(!check_src_eq(&plane_state, 0x40002, 0x40002, 1024 << 16, 768 << 16)); - FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768)); + KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple"); + KUNIT_EXPECT_TRUE(test, plane_state.visible); + KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0x40002, 0x40002, + 1024 << 16, 768 << 16)); + KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); set_src(&plane_state, 0, 0, 0x3ffff, 0x3ffff); set_crtc(&plane_state, 1022, 766, 4, 4); ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 0xffff, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, true, false); - FAIL(ret < 0, "Should succeed by clipping to exact multiple"); - FAIL_ON(!plane_state.visible); + KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple"); + KUNIT_EXPECT_TRUE(test, plane_state.visible); /* Should not be rounded to 0x20001, which would be upscaling. */ - FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16)); - FAIL_ON(!check_crtc_eq(&plane_state, 1022, 766, 2, 2)); + KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16)); + KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 1022, 766, 2, 2)); set_src(&plane_state, 0x1ffff, 0x1ffff, 0x403ffff, 0x303ffff); set_crtc(&plane_state, -2, -2, 1028, 772); ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state, 0xffff, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, false, false); - FAIL(ret < 0, "Should succeed by clipping to exact multiple"); - FAIL_ON(!plane_state.visible); - FAIL_ON(!check_src_eq(&plane_state, 0x3fffe, 0x3fffe, 1024 << 16, 768 << 16)); - FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768)); - - return 0; + KUNIT_EXPECT_FALSE_MSG(test, ret, 0, "Should succeed by clipping to exact multiple"); + KUNIT_EXPECT_TRUE(test, plane_state.visible); + KUNIT_EXPECT_TRUE(test, check_src_eq(&plane_state, 0x3fffe, 0x3fffe, + 1024 << 16, 768 << 16)); + KUNIT_EXPECT_TRUE(test, check_crtc_eq(&plane_state, 0, 0, 1024, 768)); } + +static struct kunit_case drm_plane_helper_test[] = { + KUNIT_CASE(igt_check_plane_state), + {} +}; + +static struct kunit_suite drm_plane_helper_test_suite = { + .name = "drm_plane_helper", + .test_cases = drm_plane_helper_test, +}; + +kunit_test_suite(drm_plane_helper_test_suite); + +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/tests/drm_rect_test.c b/drivers/gpu/drm/tests/drm_rect_test.c new file mode 100644 index 000000000000..c1dbefd49a4c --- /dev/null +++ b/drivers/gpu/drm/tests/drm_rect_test.c @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Test cases for the drm_rect functions + * + * Copyright (c) 2022 MaÃra Canal <mairacanal@riseup.net> + */ + +#include <kunit/test.h> + +#include <drm/drm_rect.h> + +static void igt_drm_rect_clip_scaled_div_by_zero(struct kunit *test) +{ + struct drm_rect src, dst, clip; + bool visible; + + /* + * Make sure we don't divide by zero when dst + * width/height is zero and dst and clip do not intersect. + */ + drm_rect_init(&src, 0, 0, 0, 0); + drm_rect_init(&dst, 0, 0, 0, 0); + drm_rect_init(&clip, 1, 1, 1, 1); + visible = drm_rect_clip_scaled(&src, &dst, &clip); + + KUNIT_EXPECT_FALSE_MSG(test, visible, "Destination not be visible\n"); + KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible\n"); + + drm_rect_init(&src, 0, 0, 0, 0); + drm_rect_init(&dst, 3, 3, 0, 0); + drm_rect_init(&clip, 1, 1, 1, 1); + visible = drm_rect_clip_scaled(&src, &dst, &clip); + + KUNIT_EXPECT_FALSE_MSG(test, visible, "Destination not be visible\n"); + KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible\n"); +} + +static void igt_drm_rect_clip_scaled_not_clipped(struct kunit *test) +{ + struct drm_rect src, dst, clip; + bool visible; + + /* 1:1 scaling */ + drm_rect_init(&src, 0, 0, 1 << 16, 1 << 16); + drm_rect_init(&dst, 0, 0, 1, 1); + drm_rect_init(&clip, 0, 0, 1, 1); + + visible = drm_rect_clip_scaled(&src, &dst, &clip); + + KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 1 << 16 || + src.y1 != 0 || src.y2 != 1 << 16, "Source badly clipped\n"); + KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 1 || + dst.y1 != 0 || dst.y2 != 1, "Destination badly clipped\n"); + KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n"); + KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n"); + + /* 2:1 scaling */ + drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16); + drm_rect_init(&dst, 0, 0, 1, 1); + drm_rect_init(&clip, 0, 0, 1, 1); + + visible = drm_rect_clip_scaled(&src, &dst, &clip); + + KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 2 << 16 || + src.y1 != 0 || src.y2 != 2 << 16, "Source badly clipped\n"); + KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 1 || + dst.y1 != 0 || dst.y2 != 1, "Destination badly clipped\n"); + KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n"); + KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n"); + + /* 1:2 scaling */ + drm_rect_init(&src, 0, 0, 1 << 16, 1 << 16); + drm_rect_init(&dst, 0, 0, 2, 2); + drm_rect_init(&clip, 0, 0, 2, 2); + + visible = drm_rect_clip_scaled(&src, &dst, &clip); + + KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 1 << 16 || + src.y1 != 0 || src.y2 != 1 << 16, "Source badly clipped\n"); + KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 2 || + dst.y1 != 0 || dst.y2 != 2, "Destination badly clipped\n"); + KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n"); + KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n"); +} + +static void igt_drm_rect_clip_scaled_clipped(struct kunit *test) +{ + struct drm_rect src, dst, clip; + bool visible; + + /* 1:1 scaling top/left clip */ + drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16); + drm_rect_init(&dst, 0, 0, 2, 2); + drm_rect_init(&clip, 0, 0, 1, 1); + + visible = drm_rect_clip_scaled(&src, &dst, &clip); + + KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 1 << 16 || + src.y1 != 0 || src.y2 != 1 << 16, "Source badly clipped\n"); + KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 1 || + dst.y1 != 0 || dst.y2 != 1, "Destination badly clipped\n"); + KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n"); + KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n"); + + /* 1:1 scaling bottom/right clip */ + drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16); + drm_rect_init(&dst, 0, 0, 2, 2); + drm_rect_init(&clip, 1, 1, 1, 1); + + visible = drm_rect_clip_scaled(&src, &dst, &clip); + + KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 1 << 16 || src.x2 != 2 << 16 || + src.y1 != 1 << 16 || src.y2 != 2 << 16, "Source badly clipped\n"); + KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 1 || dst.x2 != 2 || dst.y1 != 1 || + dst.y2 != 2, "Destination badly clipped\n"); + KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n"); + KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n"); + + /* 2:1 scaling top/left clip */ + drm_rect_init(&src, 0, 0, 4 << 16, 4 << 16); + drm_rect_init(&dst, 0, 0, 2, 2); + drm_rect_init(&clip, 0, 0, 1, 1); + + visible = drm_rect_clip_scaled(&src, &dst, &clip); + + KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 2 << 16 || + src.y1 != 0 || src.y2 != 2 << 16, "Source badly clipped\n"); + KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 1 || dst.y1 != 0 || + dst.y2 != 1, "Destination badly clipped\n"); + KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n"); + KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n"); + + /* 2:1 scaling bottom/right clip */ + drm_rect_init(&src, 0, 0, 4 << 16, 4 << 16); + drm_rect_init(&dst, 0, 0, 2, 2); + drm_rect_init(&clip, 1, 1, 1, 1); + + visible = drm_rect_clip_scaled(&src, &dst, &clip); + + KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 2 << 16 || src.x2 != 4 << 16 || + src.y1 != 2 << 16 || src.y2 != 4 << 16, "Source badly clipped\n"); + KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 1 || dst.x2 != 2 || dst.y1 != 1 || + dst.y2 != 2, "Destination badly clipped\n"); + KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n"); + KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n"); + + /* 1:2 scaling top/left clip */ + drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16); + drm_rect_init(&dst, 0, 0, 4, 4); + drm_rect_init(&clip, 0, 0, 2, 2); + + visible = drm_rect_clip_scaled(&src, &dst, &clip); + + KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 1 << 16 || + src.y1 != 0 || src.y2 != 1 << 16, "Source badly clipped\n"); + KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 2 || dst.y1 != 0 || + dst.y2 != 2, "Destination badly clipped\n"); + KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n"); + KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n"); + + /* 1:2 scaling bottom/right clip */ + drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16); + drm_rect_init(&dst, 0, 0, 4, 4); + drm_rect_init(&clip, 2, 2, 2, 2); + + visible = drm_rect_clip_scaled(&src, &dst, &clip); + + KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 1 << 16 || src.x2 != 2 << 16 || + src.y1 != 1 << 16 || src.y2 != 2 << 16, "Source badly clipped\n"); + KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 2 || dst.x2 != 4 || dst.y1 != 2 || + dst.y2 != 4, "Destination badly clipped\n"); + KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n"); + KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n"); +} + +static void igt_drm_rect_clip_scaled_signed_vs_unsigned(struct kunit *test) +{ + struct drm_rect src, dst, clip; + bool visible; + + /* + * 'clip.x2 - dst.x1 >= dst width' could result a negative + * src rectangle width which is no longer expected by the + * code as it's using unsigned types. This could lead to + * the clipped source rectangle appering visible when it + * should have been fully clipped. Make sure both rectangles + * end up invisible. + */ + drm_rect_init(&src, 0, 0, INT_MAX, INT_MAX); + drm_rect_init(&dst, 0, 0, 2, 2); + drm_rect_init(&clip, 3, 3, 1, 1); + + visible = drm_rect_clip_scaled(&src, &dst, &clip); + + KUNIT_EXPECT_FALSE_MSG(test, visible, "Destination should not be visible\n"); + KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible\n"); +} + +static struct kunit_case drm_rect_tests[] = { + KUNIT_CASE(igt_drm_rect_clip_scaled_div_by_zero), + KUNIT_CASE(igt_drm_rect_clip_scaled_not_clipped), + KUNIT_CASE(igt_drm_rect_clip_scaled_clipped), + KUNIT_CASE(igt_drm_rect_clip_scaled_signed_vs_unsigned), + { } +}; + +static struct kunit_suite drm_rect_test_suite = { + .name = "drm_rect", + .test_cases = drm_rect_tests, +}; + +kunit_test_suite(drm_rect_test_suite); + +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/tidss/Kconfig b/drivers/gpu/drm/tidss/Kconfig index bc4fa59b6fa9..378600806167 100644 --- a/drivers/gpu/drm/tidss/Kconfig +++ b/drivers/gpu/drm/tidss/Kconfig @@ -3,7 +3,7 @@ config DRM_TIDSS depends on DRM && OF depends on ARM || ARM64 || COMPILE_TEST select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER help The TI Keystone family SoCs introduced a new generation of Display SubSystem. There is currently three Keystone family diff --git a/drivers/gpu/drm/tidss/tidss_crtc.c b/drivers/gpu/drm/tidss/tidss_crtc.c index 2218da3b3ca3..cd3c43a6c806 100644 --- a/drivers/gpu/drm/tidss/tidss_crtc.c +++ b/drivers/gpu/drm/tidss/tidss_crtc.c @@ -8,9 +8,7 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_crtc_helper.h> -#include <drm/drm_fb_cma_helper.h> -#include <drm/drm_gem_cma_helper.h> -#include <drm/drm_plane_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_vblank.h> #include "tidss_crtc.h" diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c index dd3c6a606ae2..ad93acc9abd2 100644 --- a/drivers/gpu/drm/tidss/tidss_dispc.c +++ b/drivers/gpu/drm/tidss/tidss_dispc.c @@ -24,9 +24,9 @@ #include <drm/drm_blend.h> #include <drm/drm_fourcc.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_panel.h> #include "tidss_crtc.h" @@ -1954,16 +1954,16 @@ int dispc_plane_check(struct dispc_device *dispc, u32 hw_plane, } static -dma_addr_t dispc_plane_state_paddr(const struct drm_plane_state *state) +dma_addr_t dispc_plane_state_dma_addr(const struct drm_plane_state *state) { struct drm_framebuffer *fb = state->fb; - struct drm_gem_cma_object *gem; + struct drm_gem_dma_object *gem; u32 x = state->src_x >> 16; u32 y = state->src_y >> 16; - gem = drm_fb_cma_get_gem_obj(state->fb, 0); + gem = drm_fb_dma_get_gem_obj(state->fb, 0); - return gem->paddr + fb->offsets[0] + x * fb->format->cpp[0] + + return gem->dma_addr + fb->offsets[0] + x * fb->format->cpp[0] + y * fb->pitches[0]; } @@ -1971,16 +1971,16 @@ static dma_addr_t dispc_plane_state_p_uv_addr(const struct drm_plane_state *state) { struct drm_framebuffer *fb = state->fb; - struct drm_gem_cma_object *gem; + struct drm_gem_dma_object *gem; u32 x = state->src_x >> 16; u32 y = state->src_y >> 16; if (WARN_ON(state->fb->format->num_planes != 2)) return 0; - gem = drm_fb_cma_get_gem_obj(fb, 1); + gem = drm_fb_dma_get_gem_obj(fb, 1); - return gem->paddr + fb->offsets[1] + + return gem->dma_addr + fb->offsets[1] + (x * fb->format->cpp[1] / fb->format->hsub) + (y * fb->pitches[1] / fb->format->vsub); } @@ -1993,17 +1993,17 @@ int dispc_plane_setup(struct dispc_device *dispc, u32 hw_plane, u32 fourcc = state->fb->format->format; u16 cpp = state->fb->format->cpp[0]; u32 fb_width = state->fb->pitches[0] / cpp; - dma_addr_t paddr = dispc_plane_state_paddr(state); + dma_addr_t dma_addr = dispc_plane_state_dma_addr(state); struct dispc_scaling_params scale; dispc_vid_calc_scaling(dispc, state, &scale, lite); dispc_plane_set_pixel_format(dispc, hw_plane, fourcc); - dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_0, paddr & 0xffffffff); - dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_EXT_0, (u64)paddr >> 32); - dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_1, paddr & 0xffffffff); - dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_EXT_1, (u64)paddr >> 32); + dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_0, dma_addr & 0xffffffff); + dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_EXT_0, (u64)dma_addr >> 32); + dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_1, dma_addr & 0xffffffff); + dispc_vid_write(dispc, hw_plane, DISPC_VID_BA_EXT_1, (u64)dma_addr >> 32); dispc_vid_write(dispc, hw_plane, DISPC_VID_PICTURE_SIZE, (scale.in_w - 1) | ((scale.in_h - 1) << 16)); diff --git a/drivers/gpu/drm/tidss/tidss_drv.c b/drivers/gpu/drm/tidss/tidss_drv.c index 04cfff89ee51..15cd9b91b7e2 100644 --- a/drivers/gpu/drm/tidss/tidss_drv.c +++ b/drivers/gpu/drm/tidss/tidss_drv.c @@ -15,7 +15,7 @@ #include <drm/drm_crtc_helper.h> #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_managed.h> #include <drm/drm_module.h> #include <drm/drm_probe_helper.h> @@ -101,13 +101,13 @@ static void tidss_release(struct drm_device *ddev) drm_kms_helper_poll_fini(ddev); } -DEFINE_DRM_GEM_CMA_FOPS(tidss_fops); +DEFINE_DRM_GEM_DMA_FOPS(tidss_fops); static const struct drm_driver tidss_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .fops = &tidss_fops, .release = tidss_release, - DRM_GEM_CMA_DRIVER_OPS_VMAP, + DRM_GEM_DMA_DRIVER_OPS_VMAP, .name = "tidss", .desc = "TI Keystone DSS", .date = "20180215", diff --git a/drivers/gpu/drm/tidss/tidss_kms.c b/drivers/gpu/drm/tidss/tidss_kms.c index 666e527a0acf..b61db8f279e9 100644 --- a/drivers/gpu/drm/tidss/tidss_kms.c +++ b/drivers/gpu/drm/tidss/tidss_kms.c @@ -10,7 +10,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_crtc_helper.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_of.h> diff --git a/drivers/gpu/drm/tidss/tidss_plane.c b/drivers/gpu/drm/tidss/tidss_plane.c index 68a85a94ffcb..42d50ec5526d 100644 --- a/drivers/gpu/drm/tidss/tidss_plane.c +++ b/drivers/gpu/drm/tidss/tidss_plane.c @@ -11,7 +11,6 @@ #include <drm/drm_crtc_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_gem_atomic_helper.h> #include "tidss_crtc.h" diff --git a/drivers/gpu/drm/tilcdc/Kconfig b/drivers/gpu/drm/tilcdc/Kconfig index e315591eb36b..d3bd2d7a181e 100644 --- a/drivers/gpu/drm/tilcdc/Kconfig +++ b/drivers/gpu/drm/tilcdc/Kconfig @@ -3,7 +3,7 @@ config DRM_TILCDC tristate "DRM Support for TI LCDC Display Controller" depends on DRM && OF && ARM select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_BRIDGE select DRM_PANEL_BRIDGE select VIDEOMODE_HELPERS diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 509fbae8c9a6..b5f60b2b2d0e 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -12,10 +12,10 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_print.h> #include <drm/drm_vblank.h> @@ -64,13 +64,13 @@ static void set_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb) { struct drm_device *dev = crtc->dev; struct tilcdc_drm_private *priv = dev->dev_private; - struct drm_gem_cma_object *gem; + struct drm_gem_dma_object *gem; dma_addr_t start, end; u64 dma_base_and_ceiling; - gem = drm_fb_cma_get_gem_obj(fb, 0); + gem = drm_fb_dma_get_gem_obj(fb, 0); - start = gem->paddr + fb->offsets[0] + + start = gem->dma_addr + fb->offsets[0] + crtc->y * fb->pitches[0] + crtc->x * fb->format->cpp[0]; diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index eee3c447fbac..f72755b8ea14 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -18,7 +18,7 @@ #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_mm.h> #include <drm/drm_probe_helper.h> @@ -476,11 +476,11 @@ static void tilcdc_debugfs_init(struct drm_minor *minor) } #endif -DEFINE_DRM_GEM_CMA_FOPS(fops); +DEFINE_DRM_GEM_DMA_FOPS(fops); static const struct drm_driver tilcdc_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, - DRM_GEM_CMA_DRIVER_OPS, + DRM_GEM_DMA_DRIVER_OPS, #ifdef CONFIG_DEBUG_FS .debugfs_init = tilcdc_debugfs_init, #endif diff --git a/drivers/gpu/drm/tilcdc/tilcdc_plane.c b/drivers/gpu/drm/tilcdc/tilcdc_plane.c index 960136518814..0ccf791301cb 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_plane.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_plane.c @@ -5,7 +5,6 @@ */ #include <drm/drm_atomic.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig index 027cd87c3d0d..565957264875 100644 --- a/drivers/gpu/drm/tiny/Kconfig +++ b/drivers/gpu/drm/tiny/Kconfig @@ -3,7 +3,7 @@ config DRM_ARCPGU tristate "ARC PGU" depends on DRM && OF - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_KMS_HELPER help Choose this option if you have an ARC PGU controller. @@ -55,7 +55,7 @@ config DRM_PANEL_MIPI_DBI tristate "DRM support for MIPI DBI compatible panels" depends on DRM && SPI select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_MIPI_DBI select BACKLIGHT_CLASS_DEVICE select VIDEOMODE_HELPERS @@ -87,7 +87,7 @@ config TINYDRM_HX8357D tristate "DRM support for HX8357D display panels" depends on DRM && SPI select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_MIPI_DBI select BACKLIGHT_CLASS_DEVICE help @@ -100,7 +100,7 @@ config TINYDRM_ILI9163 tristate "DRM support for ILI9163 display panels" depends on DRM && SPI select BACKLIGHT_CLASS_DEVICE - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_KMS_HELPER select DRM_MIPI_DBI help @@ -113,7 +113,7 @@ config TINYDRM_ILI9225 tristate "DRM support for ILI9225 display panels" depends on DRM && SPI select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_MIPI_DBI help DRM driver for the following Ilitek ILI9225 panels: @@ -125,7 +125,7 @@ config TINYDRM_ILI9341 tristate "DRM support for ILI9341 display panels" depends on DRM && SPI select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_MIPI_DBI select BACKLIGHT_CLASS_DEVICE help @@ -138,7 +138,7 @@ config TINYDRM_ILI9486 tristate "DRM support for ILI9486 display panels" depends on DRM && SPI select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_MIPI_DBI select BACKLIGHT_CLASS_DEVICE help @@ -152,7 +152,7 @@ config TINYDRM_MI0283QT tristate "DRM support for MI0283QT" depends on DRM && SPI select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_MIPI_DBI select BACKLIGHT_CLASS_DEVICE help @@ -163,7 +163,7 @@ config TINYDRM_REPAPER tristate "DRM support for Pervasive Displays RePaper panels (V231)" depends on DRM && SPI select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER help DRM driver for the following Pervasive Displays panels: 1.44" TFT EPD Panel (E1144CS021) @@ -177,7 +177,7 @@ config TINYDRM_ST7586 tristate "DRM support for Sitronix ST7586 display panels" depends on DRM && SPI select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_MIPI_DBI help DRM driver for the following Sitronix ST7586 panels: @@ -189,7 +189,7 @@ config TINYDRM_ST7735R tristate "DRM support for Sitronix ST7715R/ST7735R display panels" depends on DRM && SPI select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_MIPI_DBI select BACKLIGHT_CLASS_DEVICE help diff --git a/drivers/gpu/drm/tiny/arcpgu.c b/drivers/gpu/drm/tiny/arcpgu.c index 7461cb401407..bb302a3fd6b5 100644 --- a/drivers/gpu/drm/tiny/arcpgu.c +++ b/drivers/gpu/drm/tiny/arcpgu.c @@ -11,11 +11,11 @@ #include <drm/drm_device.h> #include <drm/drm_drv.h> #include <drm/drm_edid.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_module.h> #include <drm/drm_of.h> @@ -220,14 +220,14 @@ static void arc_pgu_update(struct drm_simple_display_pipe *pipe, struct drm_plane_state *state) { struct arcpgu_drm_private *arcpgu; - struct drm_gem_cma_object *gem; + struct drm_gem_dma_object *gem; if (!pipe->plane.state->fb) return; arcpgu = pipe_to_arcpgu_priv(pipe); - gem = drm_fb_cma_get_gem_obj(pipe->plane.state->fb, 0); - arc_pgu_write(arcpgu, ARCPGU_REG_BUF0_ADDR, gem->paddr); + gem = drm_fb_dma_get_gem_obj(pipe->plane.state->fb, 0); + arc_pgu_write(arcpgu, ARCPGU_REG_BUF0_ADDR, gem->dma_addr); } static const struct drm_simple_display_pipe_funcs arc_pgu_pipe_funcs = { @@ -243,7 +243,7 @@ static const struct drm_mode_config_funcs arcpgu_drm_modecfg_funcs = { .atomic_commit = drm_atomic_helper_commit, }; -DEFINE_DRM_GEM_CMA_FOPS(arcpgu_drm_ops); +DEFINE_DRM_GEM_DMA_FOPS(arcpgu_drm_ops); static int arcpgu_load(struct arcpgu_drm_private *arcpgu) { @@ -370,7 +370,7 @@ static const struct drm_driver arcpgu_drm_driver = { .minor = 0, .patchlevel = 0, .fops = &arcpgu_drm_ops, - DRM_GEM_CMA_DRIVER_OPS, + DRM_GEM_DMA_DRIVER_OPS, #ifdef CONFIG_DEBUG_FS .debugfs_init = arcpgu_debugfs_init, #endif diff --git a/drivers/gpu/drm/tiny/bochs.c b/drivers/gpu/drm/tiny/bochs.c index 82364a0a7b18..08de13774862 100644 --- a/drivers/gpu/drm/tiny/bochs.c +++ b/drivers/gpu/drm/tiny/bochs.c @@ -583,13 +583,17 @@ static int bochs_load(struct drm_device *dev) ret = drmm_vram_helper_init(dev, bochs->fb_base, bochs->fb_size); if (ret) - return ret; + goto err_hw_fini; ret = bochs_kms_init(bochs); if (ret) - return ret; + goto err_hw_fini; return 0; + +err_hw_fini: + bochs_hw_fini(dev); + return ret; } DEFINE_DRM_GEM_FOPS(bochs_fops); @@ -664,11 +668,13 @@ static int bochs_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent ret = drm_dev_register(dev, 0); if (ret) - goto err_free_dev; + goto err_hw_fini; drm_fbdev_generic_setup(dev, 32); return ret; +err_hw_fini: + bochs_hw_fini(dev); err_free_dev: drm_dev_put(dev); return ret; diff --git a/drivers/gpu/drm/tiny/cirrus.c b/drivers/gpu/drm/tiny/cirrus.c index c4f5beea1f90..354d5e854a6f 100644 --- a/drivers/gpu/drm/tiny/cirrus.c +++ b/drivers/gpu/drm/tiny/cirrus.c @@ -316,28 +316,29 @@ static int cirrus_mode_set(struct cirrus_device *cirrus, } static int cirrus_fb_blit_rect(struct drm_framebuffer *fb, - const struct iosys_map *map, + const struct iosys_map *vmap, struct drm_rect *rect) { struct cirrus_device *cirrus = to_cirrus(fb->dev); - void __iomem *dst = cirrus->vram; - void *vmap = map->vaddr; /* TODO: Use mapping abstraction properly */ + struct iosys_map dst; int idx; if (!drm_dev_enter(&cirrus->dev, &idx)) return -ENODEV; + iosys_map_set_vaddr_iomem(&dst, cirrus->vram); + if (cirrus->cpp == fb->format->cpp[0]) { - dst += drm_fb_clip_offset(fb->pitches[0], fb->format, rect); - drm_fb_memcpy_toio(dst, fb->pitches[0], vmap, fb, rect); + iosys_map_incr(&dst, drm_fb_clip_offset(fb->pitches[0], fb->format, rect)); + drm_fb_memcpy(&dst, fb->pitches, vmap, fb, rect); } else if (fb->format->cpp[0] == 4 && cirrus->cpp == 2) { - dst += drm_fb_clip_offset(cirrus->pitch, fb->format, rect); - drm_fb_xrgb8888_to_rgb565_toio(dst, cirrus->pitch, vmap, fb, rect, false); + iosys_map_incr(&dst, drm_fb_clip_offset(cirrus->pitch, fb->format, rect)); + drm_fb_xrgb8888_to_rgb565(&dst, &cirrus->pitch, vmap, fb, rect, false); } else if (fb->format->cpp[0] == 4 && cirrus->cpp == 3) { - dst += drm_fb_clip_offset(cirrus->pitch, fb->format, rect); - drm_fb_xrgb8888_to_rgb888_toio(dst, cirrus->pitch, vmap, fb, rect); + iosys_map_incr(&dst, drm_fb_clip_offset(cirrus->pitch, fb->format, rect)); + drm_fb_xrgb8888_to_rgb888(&dst, &cirrus->pitch, vmap, fb, rect); } else { WARN_ON_ONCE("cpp mismatch"); diff --git a/drivers/gpu/drm/tiny/hx8357d.c b/drivers/gpu/drm/tiny/hx8357d.c index ebb025543f8d..57f229a785bf 100644 --- a/drivers/gpu/drm/tiny/hx8357d.c +++ b/drivers/gpu/drm/tiny/hx8357d.c @@ -20,7 +20,7 @@ #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_managed.h> #include <drm/drm_mipi_dbi.h> #include <drm/drm_modeset_helper.h> @@ -190,12 +190,12 @@ static const struct drm_display_mode yx350hv15_mode = { DRM_SIMPLE_MODE(320, 480, 60, 75), }; -DEFINE_DRM_GEM_CMA_FOPS(hx8357d_fops); +DEFINE_DRM_GEM_DMA_FOPS(hx8357d_fops); static const struct drm_driver hx8357d_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .fops = &hx8357d_fops, - DRM_GEM_CMA_DRIVER_OPS_VMAP, + DRM_GEM_DMA_DRIVER_OPS_VMAP, .debugfs_init = mipi_dbi_debugfs_init, .name = "hx8357d", .desc = "HX8357D", diff --git a/drivers/gpu/drm/tiny/ili9163.c b/drivers/gpu/drm/tiny/ili9163.c index fc8ed245b0bc..86439e50e304 100644 --- a/drivers/gpu/drm/tiny/ili9163.c +++ b/drivers/gpu/drm/tiny/ili9163.c @@ -11,7 +11,7 @@ #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_mipi_dbi.h> #include <drm/drm_modeset_helper.h> @@ -110,12 +110,12 @@ static const struct drm_display_mode yx240qv29_mode = { DRM_SIMPLE_MODE(128, 160, 28, 35), }; -DEFINE_DRM_GEM_CMA_FOPS(ili9163_fops); +DEFINE_DRM_GEM_DMA_FOPS(ili9163_fops); static struct drm_driver ili9163_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .fops = &ili9163_fops, - DRM_GEM_CMA_DRIVER_OPS_VMAP, + DRM_GEM_DMA_DRIVER_OPS_VMAP, .debugfs_init = mipi_dbi_debugfs_init, .name = "ili9163", .desc = "Ilitek ILI9163", diff --git a/drivers/gpu/drm/tiny/ili9225.c b/drivers/gpu/drm/tiny/ili9225.c index 8d686eecd5f4..a79da2b4af64 100644 --- a/drivers/gpu/drm/tiny/ili9225.c +++ b/drivers/gpu/drm/tiny/ili9225.c @@ -19,12 +19,12 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_damage_helper.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_managed.h> #include <drm/drm_mipi_dbi.h> #include <drm/drm_rect.h> @@ -78,7 +78,7 @@ static inline int ili9225_command(struct mipi_dbi *dbi, u8 cmd, u16 data) static void ili9225_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect) { - struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0); + struct drm_gem_dma_object *dma_obj = drm_fb_dma_get_gem_obj(fb, 0); struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(fb->dev); unsigned int height = rect->y2 - rect->y1; unsigned int width = rect->x2 - rect->x1; @@ -104,7 +104,7 @@ static void ili9225_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect) if (ret) goto err_msg; } else { - tr = cma_obj->vaddr; + tr = dma_obj->vaddr; } switch (dbidev->rotation) { @@ -335,12 +335,12 @@ static const struct drm_display_mode ili9225_mode = { DRM_SIMPLE_MODE(176, 220, 35, 44), }; -DEFINE_DRM_GEM_CMA_FOPS(ili9225_fops); +DEFINE_DRM_GEM_DMA_FOPS(ili9225_fops); static const struct drm_driver ili9225_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .fops = &ili9225_fops, - DRM_GEM_CMA_DRIVER_OPS_VMAP, + DRM_GEM_DMA_DRIVER_OPS_VMAP, .name = "ili9225", .desc = "Ilitek ILI9225", .date = "20171106", diff --git a/drivers/gpu/drm/tiny/ili9341.c b/drivers/gpu/drm/tiny/ili9341.c index 5b8cc770ee7b..b8826a0b086b 100644 --- a/drivers/gpu/drm/tiny/ili9341.c +++ b/drivers/gpu/drm/tiny/ili9341.c @@ -19,7 +19,7 @@ #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_managed.h> #include <drm/drm_mipi_dbi.h> #include <drm/drm_modeset_helper.h> @@ -146,12 +146,12 @@ static const struct drm_display_mode yx240qv29_mode = { DRM_SIMPLE_MODE(240, 320, 37, 49), }; -DEFINE_DRM_GEM_CMA_FOPS(ili9341_fops); +DEFINE_DRM_GEM_DMA_FOPS(ili9341_fops); static const struct drm_driver ili9341_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .fops = &ili9341_fops, - DRM_GEM_CMA_DRIVER_OPS_VMAP, + DRM_GEM_DMA_DRIVER_OPS_VMAP, .debugfs_init = mipi_dbi_debugfs_init, .name = "ili9341", .desc = "Ilitek ILI9341", diff --git a/drivers/gpu/drm/tiny/ili9486.c b/drivers/gpu/drm/tiny/ili9486.c index 6d655e18e0aa..a5b433a8e0d8 100644 --- a/drivers/gpu/drm/tiny/ili9486.c +++ b/drivers/gpu/drm/tiny/ili9486.c @@ -18,7 +18,7 @@ #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_managed.h> #include <drm/drm_mipi_dbi.h> #include <drm/drm_modeset_helper.h> @@ -159,12 +159,12 @@ static const struct drm_display_mode waveshare_mode = { DRM_SIMPLE_MODE(480, 320, 73, 49), }; -DEFINE_DRM_GEM_CMA_FOPS(ili9486_fops); +DEFINE_DRM_GEM_DMA_FOPS(ili9486_fops); static const struct drm_driver ili9486_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .fops = &ili9486_fops, - DRM_GEM_CMA_DRIVER_OPS_VMAP, + DRM_GEM_DMA_DRIVER_OPS_VMAP, .debugfs_init = mipi_dbi_debugfs_init, .name = "ili9486", .desc = "Ilitek ILI9486", diff --git a/drivers/gpu/drm/tiny/mi0283qt.c b/drivers/gpu/drm/tiny/mi0283qt.c index 5e060f6910bb..27f1bd4da2f4 100644 --- a/drivers/gpu/drm/tiny/mi0283qt.c +++ b/drivers/gpu/drm/tiny/mi0283qt.c @@ -17,7 +17,7 @@ #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_managed.h> #include <drm/drm_mipi_dbi.h> #include <drm/drm_modeset_helper.h> @@ -150,12 +150,12 @@ static const struct drm_display_mode mi0283qt_mode = { DRM_SIMPLE_MODE(320, 240, 58, 43), }; -DEFINE_DRM_GEM_CMA_FOPS(mi0283qt_fops); +DEFINE_DRM_GEM_DMA_FOPS(mi0283qt_fops); static const struct drm_driver mi0283qt_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .fops = &mi0283qt_fops, - DRM_GEM_CMA_DRIVER_OPS_VMAP, + DRM_GEM_DMA_DRIVER_OPS_VMAP, .debugfs_init = mipi_dbi_debugfs_init, .name = "mi0283qt", .desc = "Multi-Inno MI0283QT", diff --git a/drivers/gpu/drm/tiny/panel-mipi-dbi.c b/drivers/gpu/drm/tiny/panel-mipi-dbi.c index c759ff9c2c87..a76fefa8adbc 100644 --- a/drivers/gpu/drm/tiny/panel-mipi-dbi.c +++ b/drivers/gpu/drm/tiny/panel-mipi-dbi.c @@ -18,7 +18,7 @@ #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_managed.h> #include <drm/drm_mipi_dbi.h> #include <drm/drm_modes.h> @@ -217,12 +217,12 @@ static const struct drm_simple_display_pipe_funcs panel_mipi_dbi_pipe_funcs = { .update = mipi_dbi_pipe_update, }; -DEFINE_DRM_GEM_CMA_FOPS(panel_mipi_dbi_fops); +DEFINE_DRM_GEM_DMA_FOPS(panel_mipi_dbi_fops); static const struct drm_driver panel_mipi_dbi_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .fops = &panel_mipi_dbi_fops, - DRM_GEM_CMA_DRIVER_OPS_VMAP, + DRM_GEM_DMA_DRIVER_OPS_VMAP, .debugfs_init = mipi_dbi_debugfs_init, .name = "panel-mipi-dbi", .desc = "MIPI DBI compatible display panel", diff --git a/drivers/gpu/drm/tiny/repaper.c b/drivers/gpu/drm/tiny/repaper.c index 013790c45d0a..c4c1be3ac0b8 100644 --- a/drivers/gpu/drm/tiny/repaper.c +++ b/drivers/gpu/drm/tiny/repaper.c @@ -25,12 +25,12 @@ #include <drm/drm_connector.h> #include <drm/drm_damage_helper.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_format_helper.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_managed.h> #include <drm/drm_modes.h> @@ -511,8 +511,10 @@ static void repaper_get_temperature(struct repaper_epd *epd) static int repaper_fb_dirty(struct drm_framebuffer *fb) { - struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0); + struct drm_gem_dma_object *dma_obj = drm_fb_dma_get_gem_obj(fb, 0); struct repaper_epd *epd = drm_to_epd(fb->dev); + unsigned int dst_pitch = 0; + struct iosys_map dst, vmap; struct drm_rect clip; int idx, ret = 0; u8 *buf = NULL; @@ -541,7 +543,9 @@ static int repaper_fb_dirty(struct drm_framebuffer *fb) if (ret) goto out_free; - drm_fb_xrgb8888_to_mono(buf, 0, cma_obj->vaddr, fb, &clip); + iosys_map_set_vaddr(&dst, buf); + iosys_map_set_vaddr(&vmap, dma_obj->vaddr); + drm_fb_xrgb8888_to_mono(&dst, &dst_pitch, &vmap, fb, &clip); drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); @@ -903,12 +907,12 @@ static const struct drm_display_mode repaper_e2271cs021_mode = { static const u8 repaper_e2271cs021_cs[] = { 0x00, 0x00, 0x00, 0x7f, 0xff, 0xfe, 0x00, 0x00 }; -DEFINE_DRM_GEM_CMA_FOPS(repaper_fops); +DEFINE_DRM_GEM_DMA_FOPS(repaper_fops); static const struct drm_driver repaper_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .fops = &repaper_fops, - DRM_GEM_CMA_DRIVER_OPS_VMAP, + DRM_GEM_DMA_DRIVER_OPS_VMAP, .name = "repaper", .desc = "Pervasive Displays RePaper e-ink panels", .date = "20170405", diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c index 5422363690e7..a81f91814595 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -8,6 +8,7 @@ #include <linux/regulator/consumer.h> #include <drm/drm_aperture.h> +#include <drm/drm_atomic.h> #include <drm/drm_atomic_state_helper.h> #include <drm/drm_connector.h> #include <drm/drm_damage_helper.h> @@ -20,8 +21,8 @@ #include <drm/drm_gem_shmem_helper.h> #include <drm/drm_managed.h> #include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> -#include <drm/drm_simple_kms_helper.h> #define DRIVER_NAME "simpledrm" #define DRIVER_DESC "DRM driver for simple-framebuffer platform devices" @@ -198,7 +199,6 @@ simplefb_get_format_of(struct drm_device *dev, struct device_node *of_node) struct simpledrm_device { struct drm_device dev; - struct platform_device *pdev; /* clocks */ #if defined CONFIG_OF && defined CONFIG_COMMON_CLK @@ -217,14 +217,15 @@ struct simpledrm_device { unsigned int pitch; /* memory management */ - struct resource *mem; void __iomem *screen_base; /* modesetting */ uint32_t formats[8]; size_t nformats; + struct drm_plane primary_plane; + struct drm_crtc crtc; + struct drm_encoder encoder; struct drm_connector connector; - struct drm_simple_display_pipe pipe; }; static struct simpledrm_device *simpledrm_device_of_dev(struct drm_device *dev) @@ -272,7 +273,7 @@ static void simpledrm_device_release_clocks(void *res) static int simpledrm_device_init_clocks(struct simpledrm_device *sdev) { struct drm_device *dev = &sdev->dev; - struct platform_device *pdev = sdev->pdev; + struct platform_device *pdev = to_platform_device(dev->dev); struct device_node *of_node = pdev->dev.of_node; struct clk *clock; unsigned int i; @@ -370,7 +371,7 @@ static void simpledrm_device_release_regulators(void *res) static int simpledrm_device_init_regulators(struct simpledrm_device *sdev) { struct drm_device *dev = &sdev->dev; - struct platform_device *pdev = sdev->pdev; + struct platform_device *pdev = to_platform_device(dev->dev); struct device_node *of_node = pdev->dev.of_node; struct property *prop; struct regulator *regulator; @@ -451,120 +452,6 @@ static int simpledrm_device_init_regulators(struct simpledrm_device *sdev) #endif /* - * Simplefb settings - */ - -static struct drm_display_mode simpledrm_mode(unsigned int width, - unsigned int height) -{ - struct drm_display_mode mode = { SIMPLEDRM_MODE(width, height) }; - - mode.clock = mode.hdisplay * mode.vdisplay * 60 / 1000 /* kHz */; - drm_mode_set_name(&mode); - - return mode; -} - -static int simpledrm_device_init_fb(struct simpledrm_device *sdev) -{ - int width, height, stride; - const struct drm_format_info *format; - struct drm_device *dev = &sdev->dev; - struct platform_device *pdev = sdev->pdev; - const struct simplefb_platform_data *pd = dev_get_platdata(&pdev->dev); - struct device_node *of_node = pdev->dev.of_node; - - if (pd) { - width = simplefb_get_width_pd(dev, pd); - if (width < 0) - return width; - height = simplefb_get_height_pd(dev, pd); - if (height < 0) - return height; - stride = simplefb_get_stride_pd(dev, pd); - if (stride < 0) - return stride; - format = simplefb_get_format_pd(dev, pd); - if (IS_ERR(format)) - return PTR_ERR(format); - } else if (of_node) { - width = simplefb_get_width_of(dev, of_node); - if (width < 0) - return width; - height = simplefb_get_height_of(dev, of_node); - if (height < 0) - return height; - stride = simplefb_get_stride_of(dev, of_node); - if (stride < 0) - return stride; - format = simplefb_get_format_of(dev, of_node); - if (IS_ERR(format)) - return PTR_ERR(format); - } else { - drm_err(dev, "no simplefb configuration found\n"); - return -ENODEV; - } - - sdev->mode = simpledrm_mode(width, height); - sdev->format = format; - sdev->pitch = stride; - - drm_dbg_kms(dev, "display mode={" DRM_MODE_FMT "}\n", - DRM_MODE_ARG(&sdev->mode)); - drm_dbg_kms(dev, - "framebuffer format=%p4cc, size=%dx%d, stride=%d byte\n", - &format->format, width, height, stride); - - return 0; -} - -/* - * Memory management - */ - -static int simpledrm_device_init_mm(struct simpledrm_device *sdev) -{ - struct drm_device *dev = &sdev->dev; - struct platform_device *pdev = sdev->pdev; - struct resource *res, *mem; - void __iomem *screen_base; - int ret; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -EINVAL; - - ret = devm_aperture_acquire_from_firmware(dev, res->start, resource_size(res)); - if (ret) { - drm_err(dev, "could not acquire memory range %pr: error %d\n", - res, ret); - return ret; - } - - mem = devm_request_mem_region(&pdev->dev, res->start, resource_size(res), - sdev->dev.driver->name); - if (!mem) { - /* - * We cannot make this fatal. Sometimes this comes from magic - * spaces our resource handlers simply don't know about. Use - * the I/O-memory resource as-is and try to map that instead. - */ - drm_warn(dev, "could not acquire memory region %pr\n", res); - mem = res; - } - - screen_base = devm_ioremap_wc(&pdev->dev, mem->start, - resource_size(mem)); - if (!screen_base) - return -ENOMEM; - - sdev->mem = mem; - sdev->screen_base = screen_base; - - return 0; -} - -/* * Modesetting */ @@ -576,7 +463,7 @@ static int simpledrm_device_init_mm(struct simpledrm_device *sdev) * TODO: Add blit helpers for remaining formats and uncomment * constants. */ -static const uint32_t simpledrm_default_formats[] = { +static const uint32_t simpledrm_primary_plane_formats[] = { DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_RGB565, @@ -587,81 +474,52 @@ static const uint32_t simpledrm_default_formats[] = { DRM_FORMAT_ARGB2101010, }; -static const uint64_t simpledrm_format_modifiers[] = { +static const uint64_t simpledrm_primary_plane_format_modifiers[] = { DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID }; -static int simpledrm_connector_helper_get_modes(struct drm_connector *connector) +static int simpledrm_primary_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_atomic_state *new_state) { - struct simpledrm_device *sdev = simpledrm_device_of_dev(connector->dev); - struct drm_display_mode *mode; - - mode = drm_mode_duplicate(connector->dev, &sdev->mode); - if (!mode) - return 0; - - if (mode->name[0] == '\0') - drm_mode_set_name(mode); - - mode->type |= DRM_MODE_TYPE_PREFERRED; - drm_mode_probed_add(connector, mode); - - if (mode->width_mm) - connector->display_info.width_mm = mode->width_mm; - if (mode->height_mm) - connector->display_info.height_mm = mode->height_mm; - - return 1; -} - -static const struct drm_connector_helper_funcs simpledrm_connector_helper_funcs = { - .get_modes = simpledrm_connector_helper_get_modes, -}; - -static const struct drm_connector_funcs simpledrm_connector_funcs = { - .reset = drm_atomic_helper_connector_reset, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = drm_connector_cleanup, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane); + struct drm_crtc *new_crtc = new_plane_state->crtc; + struct drm_crtc_state *new_crtc_state = NULL; + int ret; -static enum drm_mode_status -simpledrm_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe, - const struct drm_display_mode *mode) -{ - struct simpledrm_device *sdev = simpledrm_device_of_dev(pipe->crtc.dev); + if (new_crtc) + new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_crtc); - if (mode->hdisplay != sdev->mode.hdisplay && - mode->vdisplay != sdev->mode.vdisplay) - return MODE_ONE_SIZE; - else if (mode->hdisplay != sdev->mode.hdisplay) - return MODE_ONE_WIDTH; - else if (mode->vdisplay != sdev->mode.vdisplay) - return MODE_ONE_HEIGHT; + ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, false); + if (ret) + return ret; + else if (!new_plane_state->visible) + return 0; - return MODE_OK; + return 0; } -static void -simpledrm_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +static void simpledrm_primary_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_state *old_state) { - struct simpledrm_device *sdev = simpledrm_device_of_dev(pipe->crtc.dev); + struct drm_plane_state *plane_state = plane->state; + struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(old_state, plane); struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); struct drm_framebuffer *fb = plane_state->fb; - void *vmap = shadow_plane_state->data[0].vaddr; /* TODO: Use mapping abstraction */ - struct drm_device *dev = &sdev->dev; - void __iomem *dst = sdev->screen_base; + struct drm_device *dev = plane->dev; + struct simpledrm_device *sdev = simpledrm_device_of_dev(dev); + struct iosys_map dst = IOSYS_MAP_INIT_VADDR(sdev->screen_base); struct drm_rect src_clip, dst_clip; int idx; if (!fb) return; - drm_rect_fp_to_int(&src_clip, &plane_state->src); + if (!drm_atomic_helper_damage_merged(old_plane_state, plane_state, &src_clip)) + return; dst_clip = plane_state->dst; if (!drm_rect_intersect(&dst_clip, &src_clip)) @@ -670,17 +528,18 @@ simpledrm_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, if (!drm_dev_enter(dev, &idx)) return; - dst += drm_fb_clip_offset(sdev->pitch, sdev->format, &dst_clip); - drm_fb_blit_toio(dst, sdev->pitch, sdev->format->format, vmap, fb, &src_clip); + iosys_map_incr(&dst, drm_fb_clip_offset(sdev->pitch, sdev->format, &dst_clip)); + drm_fb_blit(&dst, &sdev->pitch, sdev->format->format, shadow_plane_state->data, fb, + &src_clip); drm_dev_exit(idx); } -static void -simpledrm_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe) +static void simpledrm_primary_plane_helper_atomic_disable(struct drm_plane *plane, + struct drm_atomic_state *old_state) { - struct simpledrm_device *sdev = simpledrm_device_of_dev(pipe->crtc.dev); - struct drm_device *dev = &sdev->dev; + struct drm_device *dev = plane->dev; + struct simpledrm_device *sdev = simpledrm_device_of_dev(dev); int idx; if (!drm_dev_enter(dev, &idx)) @@ -692,46 +551,105 @@ simpledrm_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe) drm_dev_exit(idx); } -static void -simpledrm_simple_display_pipe_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *old_plane_state) +static const struct drm_plane_helper_funcs simpledrm_primary_plane_helper_funcs = { + DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, + .atomic_check = simpledrm_primary_plane_helper_atomic_check, + .atomic_update = simpledrm_primary_plane_helper_atomic_update, + .atomic_disable = simpledrm_primary_plane_helper_atomic_disable, +}; + +static const struct drm_plane_funcs simpledrm_primary_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + DRM_GEM_SHADOW_PLANE_FUNCS, +}; + +static enum drm_mode_status simpledrm_crtc_helper_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) { - struct simpledrm_device *sdev = simpledrm_device_of_dev(pipe->crtc.dev); - struct drm_plane_state *plane_state = pipe->plane.state; - struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); - void *vmap = shadow_plane_state->data[0].vaddr; /* TODO: Use mapping abstraction */ - struct drm_framebuffer *fb = plane_state->fb; - struct drm_device *dev = &sdev->dev; - void __iomem *dst = sdev->screen_base; - struct drm_rect src_clip, dst_clip; - int idx; + struct simpledrm_device *sdev = simpledrm_device_of_dev(crtc->dev); - if (!fb) - return; + if (mode->hdisplay != sdev->mode.hdisplay && + mode->vdisplay != sdev->mode.vdisplay) + return MODE_ONE_SIZE; + else if (mode->hdisplay != sdev->mode.hdisplay) + return MODE_ONE_WIDTH; + else if (mode->vdisplay != sdev->mode.vdisplay) + return MODE_ONE_HEIGHT; - if (!drm_atomic_helper_damage_merged(old_plane_state, plane_state, &src_clip)) - return; + return MODE_OK; +} - dst_clip = plane_state->dst; - if (!drm_rect_intersect(&dst_clip, &src_clip)) - return; +static int simpledrm_crtc_helper_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_state *new_state) +{ + struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc); + int ret; - if (!drm_dev_enter(dev, &idx)) - return; + ret = drm_atomic_helper_check_crtc_state(new_crtc_state, false); + if (ret) + return ret; - dst += drm_fb_clip_offset(sdev->pitch, sdev->format, &dst_clip); - drm_fb_blit_toio(dst, sdev->pitch, sdev->format->format, vmap, fb, &src_clip); + return drm_atomic_add_affected_planes(new_state, crtc); +} - drm_dev_exit(idx); +/* + * The CRTC is always enabled. Screen updates are performed by + * the primary plane's atomic_update function. Disabling clears + * the screen in the primary plane's atomic_disable function. + */ +static const struct drm_crtc_helper_funcs simpledrm_crtc_helper_funcs = { + .mode_valid = simpledrm_crtc_helper_mode_valid, + .atomic_check = simpledrm_crtc_helper_atomic_check, +}; + +static const struct drm_crtc_funcs simpledrm_crtc_funcs = { + .reset = drm_atomic_helper_crtc_reset, + .destroy = drm_crtc_cleanup, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, +}; + +static const struct drm_encoder_funcs simpledrm_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static int simpledrm_connector_helper_get_modes(struct drm_connector *connector) +{ + struct simpledrm_device *sdev = simpledrm_device_of_dev(connector->dev); + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, &sdev->mode); + if (!mode) + return 0; + + if (mode->name[0] == '\0') + drm_mode_set_name(mode); + + mode->type |= DRM_MODE_TYPE_PREFERRED; + drm_mode_probed_add(connector, mode); + + if (mode->width_mm) + connector->display_info.width_mm = mode->width_mm; + if (mode->height_mm) + connector->display_info.height_mm = mode->height_mm; + + return 1; } -static const struct drm_simple_display_pipe_funcs -simpledrm_simple_display_pipe_funcs = { - .mode_valid = simpledrm_simple_display_pipe_mode_valid, - .enable = simpledrm_simple_display_pipe_enable, - .disable = simpledrm_simple_display_pipe_disable, - .update = simpledrm_simple_display_pipe_update, - DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, +static const struct drm_connector_helper_funcs simpledrm_connector_helper_funcs = { + .get_modes = simpledrm_connector_helper_get_modes, +}; + +static const struct drm_connector_funcs simpledrm_connector_funcs = { + .reset = drm_atomic_helper_connector_reset, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; static const struct drm_mode_config_funcs simpledrm_mode_config_funcs = { @@ -740,6 +658,21 @@ static const struct drm_mode_config_funcs simpledrm_mode_config_funcs = { .atomic_commit = drm_atomic_helper_commit, }; +/* + * Init / Cleanup + */ + +static struct drm_display_mode simpledrm_mode(unsigned int width, + unsigned int height) +{ + struct drm_display_mode mode = { SIMPLEDRM_MODE(width, height) }; + + mode.clock = mode.hdisplay * mode.vdisplay * 60 / 1000 /* kHz */; + drm_mode_set_name(&mode); + + return mode; +} + static const uint32_t *simpledrm_device_formats(struct simpledrm_device *sdev, size_t *nformats_out) { @@ -754,10 +687,10 @@ static const uint32_t *simpledrm_device_formats(struct simpledrm_device *sdev, sdev->nformats = 1; /* default formats go second */ - for (i = 0; i < ARRAY_SIZE(simpledrm_default_formats); ++i) { - if (simpledrm_default_formats[i] == sdev->format->format) + for (i = 0; i < ARRAY_SIZE(simpledrm_primary_plane_formats); ++i) { + if (simpledrm_primary_plane_formats[i] == sdev->format->format) continue; /* native format already went first */ - sdev->formats[sdev->nformats] = simpledrm_default_formats[i]; + sdev->formats[sdev->nformats] = simpledrm_primary_plane_formats[i]; sdev->nformats++; } @@ -779,88 +712,182 @@ out: return sdev->formats; } -static int simpledrm_device_init_modeset(struct simpledrm_device *sdev) +static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv, + struct platform_device *pdev) { - struct drm_device *dev = &sdev->dev; - struct drm_display_mode *mode = &sdev->mode; - struct drm_connector *connector = &sdev->connector; - struct drm_simple_display_pipe *pipe = &sdev->pipe; + const struct simplefb_platform_data *pd = dev_get_platdata(&pdev->dev); + struct device_node *of_node = pdev->dev.of_node; + struct simpledrm_device *sdev; + struct drm_device *dev; + int width, height, stride; + const struct drm_format_info *format; + struct resource *res, *mem; + void __iomem *screen_base; + struct drm_plane *primary_plane; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + struct drm_connector *connector; unsigned long max_width, max_height; const uint32_t *formats; size_t nformats; int ret; - ret = drmm_mode_config_init(dev); + sdev = devm_drm_dev_alloc(&pdev->dev, drv, struct simpledrm_device, dev); + if (IS_ERR(sdev)) + return ERR_CAST(sdev); + dev = &sdev->dev; + platform_set_drvdata(pdev, sdev); + + /* + * Hardware settings + */ + + ret = simpledrm_device_init_clocks(sdev); if (ret) - return ret; + return ERR_PTR(ret); + ret = simpledrm_device_init_regulators(sdev); + if (ret) + return ERR_PTR(ret); - max_width = max_t(unsigned long, mode->hdisplay, DRM_SHADOW_PLANE_MAX_WIDTH); - max_height = max_t(unsigned long, mode->vdisplay, DRM_SHADOW_PLANE_MAX_HEIGHT); + if (pd) { + width = simplefb_get_width_pd(dev, pd); + if (width < 0) + return ERR_PTR(width); + height = simplefb_get_height_pd(dev, pd); + if (height < 0) + return ERR_PTR(height); + stride = simplefb_get_stride_pd(dev, pd); + if (stride < 0) + return ERR_PTR(stride); + format = simplefb_get_format_pd(dev, pd); + if (IS_ERR(format)) + return ERR_CAST(format); + } else if (of_node) { + width = simplefb_get_width_of(dev, of_node); + if (width < 0) + return ERR_PTR(width); + height = simplefb_get_height_of(dev, of_node); + if (height < 0) + return ERR_PTR(height); + stride = simplefb_get_stride_of(dev, of_node); + if (stride < 0) + return ERR_PTR(stride); + format = simplefb_get_format_of(dev, of_node); + if (IS_ERR(format)) + return ERR_CAST(format); + } else { + drm_err(dev, "no simplefb configuration found\n"); + return ERR_PTR(-ENODEV); + } + if (!stride) + stride = DIV_ROUND_UP(drm_format_info_bpp(format, 0) * width, 8); - dev->mode_config.min_width = mode->hdisplay; - dev->mode_config.max_width = max_width; - dev->mode_config.min_height = mode->vdisplay; - dev->mode_config.max_height = max_height; - dev->mode_config.preferred_depth = sdev->format->cpp[0] * 8; - dev->mode_config.funcs = &simpledrm_mode_config_funcs; + sdev->mode = simpledrm_mode(width, height); + sdev->format = format; + sdev->pitch = stride; - ret = drm_connector_init(dev, connector, &simpledrm_connector_funcs, - DRM_MODE_CONNECTOR_Unknown); - if (ret) - return ret; - drm_connector_helper_add(connector, &simpledrm_connector_helper_funcs); - drm_connector_set_panel_orientation_with_quirk(connector, - DRM_MODE_PANEL_ORIENTATION_UNKNOWN, - mode->hdisplay, mode->vdisplay); + drm_dbg(dev, "display mode={" DRM_MODE_FMT "}\n", DRM_MODE_ARG(&sdev->mode)); + drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, stride=%d byte\n", + &format->format, width, height, stride); - formats = simpledrm_device_formats(sdev, &nformats); + /* + * Memory management + */ - ret = drm_simple_display_pipe_init(dev, pipe, &simpledrm_simple_display_pipe_funcs, - formats, nformats, simpledrm_format_modifiers, - connector); - if (ret) - return ret; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return ERR_PTR(-EINVAL); - drm_plane_enable_fb_damage_clips(&pipe->plane); + ret = devm_aperture_acquire_from_firmware(dev, res->start, resource_size(res)); + if (ret) { + drm_err(dev, "could not acquire memory range %pr: error %d\n", res, ret); + return ERR_PTR(ret); + } - drm_mode_config_reset(dev); + mem = devm_request_mem_region(&pdev->dev, res->start, resource_size(res), drv->name); + if (!mem) { + /* + * We cannot make this fatal. Sometimes this comes from magic + * spaces our resource handlers simply don't know about. Use + * the I/O-memory resource as-is and try to map that instead. + */ + drm_warn(dev, "could not acquire memory region %pr\n", res); + mem = res; + } - return 0; -} + screen_base = devm_ioremap_wc(&pdev->dev, mem->start, resource_size(mem)); + if (!screen_base) + return ERR_PTR(-ENOMEM); + sdev->screen_base = screen_base; -/* - * Init / Cleanup - */ + /* + * Modesetting + */ -static struct simpledrm_device * -simpledrm_device_create(struct drm_driver *drv, struct platform_device *pdev) -{ - struct simpledrm_device *sdev; - int ret; + ret = drmm_mode_config_init(dev); + if (ret) + return ERR_PTR(ret); - sdev = devm_drm_dev_alloc(&pdev->dev, drv, struct simpledrm_device, - dev); - if (IS_ERR(sdev)) - return ERR_CAST(sdev); - sdev->pdev = pdev; - platform_set_drvdata(pdev, sdev); + max_width = max_t(unsigned long, width, DRM_SHADOW_PLANE_MAX_WIDTH); + max_height = max_t(unsigned long, height, DRM_SHADOW_PLANE_MAX_HEIGHT); - ret = simpledrm_device_init_clocks(sdev); + dev->mode_config.min_width = width; + dev->mode_config.max_width = max_width; + dev->mode_config.min_height = height; + dev->mode_config.max_height = max_height; + dev->mode_config.preferred_depth = format->cpp[0] * 8; + dev->mode_config.funcs = &simpledrm_mode_config_funcs; + + /* Primary plane */ + + formats = simpledrm_device_formats(sdev, &nformats); + + primary_plane = &sdev->primary_plane; + ret = drm_universal_plane_init(dev, primary_plane, 0, &simpledrm_primary_plane_funcs, + formats, nformats, + simpledrm_primary_plane_format_modifiers, + DRM_PLANE_TYPE_PRIMARY, NULL); if (ret) return ERR_PTR(ret); - ret = simpledrm_device_init_regulators(sdev); + drm_plane_helper_add(primary_plane, &simpledrm_primary_plane_helper_funcs); + drm_plane_enable_fb_damage_clips(primary_plane); + + /* CRTC */ + + crtc = &sdev->crtc; + ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, + &simpledrm_crtc_funcs, NULL); if (ret) return ERR_PTR(ret); - ret = simpledrm_device_init_fb(sdev); + drm_crtc_helper_add(crtc, &simpledrm_crtc_helper_funcs); + + /* Encoder */ + + encoder = &sdev->encoder; + ret = drm_encoder_init(dev, encoder, &simpledrm_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); if (ret) return ERR_PTR(ret); - ret = simpledrm_device_init_mm(sdev); + encoder->possible_crtcs = drm_crtc_mask(crtc); + + /* Connector */ + + connector = &sdev->connector; + ret = drm_connector_init(dev, connector, &simpledrm_connector_funcs, + DRM_MODE_CONNECTOR_Unknown); if (ret) return ERR_PTR(ret); - ret = simpledrm_device_init_modeset(sdev); + drm_connector_helper_add(connector, &simpledrm_connector_helper_funcs); + drm_connector_set_panel_orientation_with_quirk(connector, + DRM_MODE_PANEL_ORIENTATION_UNKNOWN, + width, height); + + ret = drm_connector_attach_encoder(connector, encoder); if (ret) return ERR_PTR(ret); + drm_mode_config_reset(dev); + return sdev; } diff --git a/drivers/gpu/drm/tiny/st7586.c b/drivers/gpu/drm/tiny/st7586.c index 8eddb020c43e..b6f620b902e6 100644 --- a/drivers/gpu/drm/tiny/st7586.c +++ b/drivers/gpu/drm/tiny/st7586.c @@ -15,12 +15,12 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_damage_helper.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_format_helper.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_managed.h> #include <drm/drm_mipi_dbi.h> @@ -69,12 +69,15 @@ static void st7586_xrgb8888_to_gray332(u8 *dst, void *vaddr, size_t len = (clip->x2 - clip->x1) * (clip->y2 - clip->y1); unsigned int x, y; u8 *src, *buf, val; + struct iosys_map dst_map, vmap; buf = kmalloc(len, GFP_KERNEL); if (!buf) return; - drm_fb_xrgb8888_to_gray8(buf, 0, vaddr, fb, clip); + iosys_map_set_vaddr(&dst_map, buf); + iosys_map_set_vaddr(&vmap, vaddr); + drm_fb_xrgb8888_to_gray8(&dst_map, NULL, &vmap, fb, clip); src = buf; for (y = clip->y1; y < clip->y2; y++) { @@ -92,8 +95,8 @@ static void st7586_xrgb8888_to_gray332(u8 *dst, void *vaddr, static int st7586_buf_copy(void *dst, struct drm_framebuffer *fb, struct drm_rect *clip) { - struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0); - void *src = cma_obj->vaddr; + struct drm_gem_dma_object *dma_obj = drm_fb_dma_get_gem_obj(fb, 0); + void *src = dma_obj->vaddr; int ret = 0; ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); @@ -269,12 +272,12 @@ static const struct drm_display_mode st7586_mode = { DRM_SIMPLE_MODE(178, 128, 37, 27), }; -DEFINE_DRM_GEM_CMA_FOPS(st7586_fops); +DEFINE_DRM_GEM_DMA_FOPS(st7586_fops); static const struct drm_driver st7586_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .fops = &st7586_fops, - DRM_GEM_CMA_DRIVER_OPS_VMAP, + DRM_GEM_DMA_DRIVER_OPS_VMAP, .debugfs_init = mipi_dbi_debugfs_init, .name = "st7586", .desc = "Sitronix ST7586", diff --git a/drivers/gpu/drm/tiny/st7735r.c b/drivers/gpu/drm/tiny/st7735r.c index e0f02d367d88..d2042a0f02dd 100644 --- a/drivers/gpu/drm/tiny/st7735r.c +++ b/drivers/gpu/drm/tiny/st7735r.c @@ -20,7 +20,7 @@ #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_managed.h> #include <drm/drm_mipi_dbi.h> @@ -151,12 +151,12 @@ static const struct st7735r_cfg rh128128t_cfg = { .rgb = true, }; -DEFINE_DRM_GEM_CMA_FOPS(st7735r_fops); +DEFINE_DRM_GEM_DMA_FOPS(st7735r_fops); static const struct drm_driver st7735r_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .fops = &st7735r_fops, - DRM_GEM_CMA_DRIVER_OPS_VMAP, + DRM_GEM_DMA_DRIVER_OPS_VMAP, .debugfs_init = mipi_dbi_debugfs_init, .name = "st7735r", .desc = "Sitronix ST7735R", diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 97184c333526..590110fdf59c 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -117,12 +117,13 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx, struct ttm_place *hop) { - struct ttm_resource_manager *old_man, *new_man; struct ttm_device *bdev = bo->bdev; + bool old_use_tt, new_use_tt; int ret; - old_man = ttm_manager_type(bdev, bo->resource->mem_type); - new_man = ttm_manager_type(bdev, mem->mem_type); + old_use_tt = bo->resource && + ttm_manager_type(bdev, bo->resource->mem_type)->use_tt; + new_use_tt = ttm_manager_type(bdev, mem->mem_type)->use_tt; ttm_bo_unmap_virtual(bo); @@ -130,11 +131,11 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, * Create and bind a ttm if required. */ - if (new_man->use_tt) { + if (new_use_tt) { /* Zero init the new TTM structure if the old location should * have used one as well. */ - ret = ttm_tt_create(bo, old_man->use_tt); + ret = ttm_tt_create(bo, old_use_tt); if (ret) goto out_err; @@ -160,8 +161,7 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, return 0; out_err: - new_man = ttm_manager_type(bdev, bo->resource->mem_type); - if (!new_man->use_tt) + if (!old_use_tt) ttm_bo_tt_destroy(bo); return ret; @@ -904,7 +904,7 @@ int ttm_bo_validate(struct ttm_buffer_object *bo, /* * Check whether we need to move buffer. */ - if (!ttm_resource_compat(bo->resource, placement)) { + if (!bo->resource || !ttm_resource_compat(bo->resource, placement)) { ret = ttm_bo_move_buffer(bo, placement, ctx); if (ret) return ret; @@ -921,36 +921,61 @@ int ttm_bo_validate(struct ttm_buffer_object *bo, } EXPORT_SYMBOL(ttm_bo_validate); -int ttm_bo_init_reserved(struct ttm_device *bdev, - struct ttm_buffer_object *bo, - size_t size, - enum ttm_bo_type type, - struct ttm_placement *placement, - uint32_t page_alignment, - struct ttm_operation_ctx *ctx, - struct sg_table *sg, - struct dma_resv *resv, +/** + * ttm_bo_init_reserved + * + * @bdev: Pointer to a ttm_device struct. + * @bo: Pointer to a ttm_buffer_object to be initialized. + * @type: Requested type of buffer object. + * @placement: Initial placement for buffer object. + * @alignment: Data alignment in pages. + * @ctx: TTM operation context for memory allocation. + * @sg: Scatter-gather table. + * @resv: Pointer to a dma_resv, or NULL to let ttm allocate one. + * @destroy: Destroy function. Use NULL for kfree(). + * + * This function initializes a pre-allocated struct ttm_buffer_object. + * As this object may be part of a larger structure, this function, + * together with the @destroy function, enables driver-specific objects + * derived from a ttm_buffer_object. + * + * On successful return, the caller owns an object kref to @bo. The kref and + * list_kref are usually set to 1, but note that in some situations, other + * tasks may already be holding references to @bo as well. + * Furthermore, if resv == NULL, the buffer's reservation lock will be held, + * and it is the caller's responsibility to call ttm_bo_unreserve. + * + * If a failure occurs, the function will call the @destroy function. Thus, + * after a failure, dereferencing @bo is illegal and will likely cause memory + * corruption. + * + * Returns + * -ENOMEM: Out of memory. + * -EINVAL: Invalid placement flags. + * -ERESTARTSYS: Interrupted by signal while sleeping waiting for resources. + */ +int ttm_bo_init_reserved(struct ttm_device *bdev, struct ttm_buffer_object *bo, + enum ttm_bo_type type, struct ttm_placement *placement, + uint32_t alignment, struct ttm_operation_ctx *ctx, + struct sg_table *sg, struct dma_resv *resv, void (*destroy) (struct ttm_buffer_object *)) { static const struct ttm_place sys_mem = { .mem_type = TTM_PL_SYSTEM }; - bool locked; int ret; - bo->destroy = destroy; kref_init(&bo->kref); INIT_LIST_HEAD(&bo->ddestroy); bo->bdev = bdev; bo->type = type; - bo->page_alignment = page_alignment; + bo->page_alignment = alignment; + bo->destroy = destroy; bo->pin_count = 0; bo->sg = sg; bo->bulk_move = NULL; - if (resv) { + if (resv) bo->base.resv = resv; - dma_resv_assert_held(bo->base.resv); - } else { + else bo->base.resv = &bo->base._resv; - } atomic_inc(&ttm_glob.bo_count); ret = ttm_resource_alloc(bo, &sys_mem, &bo->resource); @@ -963,50 +988,84 @@ int ttm_bo_init_reserved(struct ttm_device *bdev, * For ttm_bo_type_device buffers, allocate * address space from the device. */ - if (bo->type == ttm_bo_type_device || - bo->type == ttm_bo_type_sg) + if (bo->type == ttm_bo_type_device || bo->type == ttm_bo_type_sg) { ret = drm_vma_offset_add(bdev->vma_manager, &bo->base.vma_node, - bo->resource->num_pages); + PFN_UP(bo->base.size)); + if (ret) + goto err_put; + } /* passed reservation objects should already be locked, * since otherwise lockdep will be angered in radeon. */ - if (!resv) { - locked = dma_resv_trylock(bo->base.resv); - WARN_ON(!locked); - } + if (!resv) + WARN_ON(!dma_resv_trylock(bo->base.resv)); + else + dma_resv_assert_held(resv); - if (likely(!ret)) - ret = ttm_bo_validate(bo, placement, ctx); + ret = ttm_bo_validate(bo, placement, ctx); + if (unlikely(ret)) + goto err_unlock; - if (unlikely(ret)) { - if (!resv) - ttm_bo_unreserve(bo); + return 0; - ttm_bo_put(bo); - return ret; - } +err_unlock: + if (!resv) + dma_resv_unlock(bo->base.resv); +err_put: + ttm_bo_put(bo); return ret; } EXPORT_SYMBOL(ttm_bo_init_reserved); -int ttm_bo_init(struct ttm_device *bdev, - struct ttm_buffer_object *bo, - size_t size, - enum ttm_bo_type type, - struct ttm_placement *placement, - uint32_t page_alignment, - bool interruptible, - struct sg_table *sg, - struct dma_resv *resv, - void (*destroy) (struct ttm_buffer_object *)) +/** + * ttm_bo_init_validate + * + * @bdev: Pointer to a ttm_device struct. + * @bo: Pointer to a ttm_buffer_object to be initialized. + * @type: Requested type of buffer object. + * @placement: Initial placement for buffer object. + * @alignment: Data alignment in pages. + * @interruptible: If needing to sleep to wait for GPU resources, + * sleep interruptible. + * pinned in physical memory. If this behaviour is not desired, this member + * holds a pointer to a persistent shmem object. Typically, this would + * point to the shmem object backing a GEM object if TTM is used to back a + * GEM user interface. + * @sg: Scatter-gather table. + * @resv: Pointer to a dma_resv, or NULL to let ttm allocate one. + * @destroy: Destroy function. Use NULL for kfree(). + * + * This function initializes a pre-allocated struct ttm_buffer_object. + * As this object may be part of a larger structure, this function, + * together with the @destroy function, + * enables driver-specific objects derived from a ttm_buffer_object. + * + * On successful return, the caller owns an object kref to @bo. The kref and + * list_kref are usually set to 1, but note that in some situations, other + * tasks may already be holding references to @bo as well. + * + * If a failure occurs, the function will call the @destroy function, Thus, + * after a failure, dereferencing @bo is illegal and will likely cause memory + * corruption. + * + * Returns + * -ENOMEM: Out of memory. + * -EINVAL: Invalid placement flags. + * -ERESTARTSYS: Interrupted by signal while sleeping waiting for resources. + */ +int ttm_bo_init_validate(struct ttm_device *bdev, struct ttm_buffer_object *bo, + enum ttm_bo_type type, struct ttm_placement *placement, + uint32_t alignment, bool interruptible, + struct sg_table *sg, struct dma_resv *resv, + void (*destroy) (struct ttm_buffer_object *)) { struct ttm_operation_ctx ctx = { interruptible, false }; int ret; - ret = ttm_bo_init_reserved(bdev, bo, size, type, placement, - page_alignment, &ctx, sg, resv, destroy); + ret = ttm_bo_init_reserved(bdev, bo, type, placement, alignment, &ctx, + sg, resv, destroy); if (ret) return ret; @@ -1015,7 +1074,7 @@ int ttm_bo_init(struct ttm_device *bdev, return 0; } -EXPORT_SYMBOL(ttm_bo_init); +EXPORT_SYMBOL(ttm_bo_init_validate); /* * buffer object vm functions. diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 1cbfb00c1d65..1530982338e9 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -137,8 +137,7 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, ttm_manager_type(bo->bdev, dst_mem->mem_type); struct ttm_tt *ttm = bo->ttm; struct ttm_resource *src_mem = bo->resource; - struct ttm_resource_manager *src_man = - ttm_manager_type(bdev, src_mem->mem_type); + struct ttm_resource_manager *src_man; union { struct ttm_kmap_iter_tt tt; struct ttm_kmap_iter_linear_io io; @@ -147,6 +146,10 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, bool clear; int ret = 0; + if (!src_mem) + return 0; + + src_man = ttm_manager_type(bdev, src_mem->mem_type); if (ttm && ((ttm->page_flags & TTM_TT_FLAG_SWAPPED) || dst_man->use_tt)) { ret = ttm_tt_populate(bdev, ttm, ctx); diff --git a/drivers/gpu/drm/tve200/Kconfig b/drivers/gpu/drm/tve200/Kconfig index 47a7dbe6c114..11e865be81c6 100644 --- a/drivers/gpu/drm/tve200/Kconfig +++ b/drivers/gpu/drm/tve200/Kconfig @@ -8,7 +8,7 @@ config DRM_TVE200 select DRM_BRIDGE select DRM_PANEL_BRIDGE select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE help Choose this option for DRM support for the Faraday TV Encoder diff --git a/drivers/gpu/drm/tve200/tve200_display.c b/drivers/gpu/drm/tve200/tve200_display.c index 771bad881714..37bdd976ae59 100644 --- a/drivers/gpu/drm/tve200/tve200_display.c +++ b/drivers/gpu/drm/tve200/tve200_display.c @@ -15,11 +15,11 @@ #include <linux/of_graph.h> #include <linux/delay.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_panel.h> #include <drm/drm_vblank.h> @@ -90,7 +90,7 @@ static int tve200_display_check(struct drm_simple_display_pipe *pipe, } if (fb) { - u32 offset = drm_fb_cma_get_gem_addr(fb, pstate, 0); + u32 offset = drm_fb_dma_get_gem_addr(fb, pstate, 0); /* FB base address must be dword aligned. */ if (offset & 3) { @@ -267,14 +267,14 @@ static void tve200_display_update(struct drm_simple_display_pipe *pipe, if (fb) { /* For RGB, the Y component is used as base address */ - writel(drm_fb_cma_get_gem_addr(fb, pstate, 0), + writel(drm_fb_dma_get_gem_addr(fb, pstate, 0), priv->regs + TVE200_Y_FRAME_BASE_ADDR); /* For three plane YUV we need two more addresses */ if (fb->format->format == DRM_FORMAT_YUV420) { - writel(drm_fb_cma_get_gem_addr(fb, pstate, 1), + writel(drm_fb_dma_get_gem_addr(fb, pstate, 1), priv->regs + TVE200_U_FRAME_BASE_ADDR); - writel(drm_fb_cma_get_gem_addr(fb, pstate, 2), + writel(drm_fb_dma_get_gem_addr(fb, pstate, 2), priv->regs + TVE200_V_FRAME_BASE_ADDR); } } diff --git a/drivers/gpu/drm/tve200/tve200_drv.c b/drivers/gpu/drm/tve200/tve200_drv.c index 6d9d2921abf4..79d790ae1670 100644 --- a/drivers/gpu/drm/tve200/tve200_drv.c +++ b/drivers/gpu/drm/tve200/tve200_drv.c @@ -39,9 +39,8 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_module.h> #include <drm/drm_of.h> @@ -135,7 +134,7 @@ finish: return ret; } -DEFINE_DRM_GEM_CMA_FOPS(drm_fops); +DEFINE_DRM_GEM_DMA_FOPS(drm_fops); static const struct drm_driver tve200_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, @@ -147,7 +146,7 @@ static const struct drm_driver tve200_drm_driver = { .major = 1, .minor = 0, .patchlevel = 0, - DRM_GEM_CMA_DRIVER_OPS, + DRM_GEM_DMA_DRIVER_OPS, }; static int tve200_probe(struct platform_device *pdev) diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h index cc16a13316e4..28aaf75d71cf 100644 --- a/drivers/gpu/drm/udl/udl_drv.h +++ b/drivers/gpu/drm/udl/udl_drv.h @@ -34,14 +34,14 @@ struct udl_device; struct urb_node { struct list_head entry; struct udl_device *dev; - struct delayed_work release_urb_work; struct urb *urb; }; struct urb_list { struct list_head list; + struct list_head in_flight; spinlock_t lock; - struct semaphore limit_sem; + wait_queue_head_t sleep; int available; int count; size_t size; @@ -75,9 +75,17 @@ static inline struct usb_device *udl_to_usb_device(struct udl_device *udl) int udl_modeset_init(struct drm_device *dev); struct drm_connector *udl_connector_init(struct drm_device *dev); -struct urb *udl_get_urb(struct drm_device *dev); +struct urb *udl_get_urb_timeout(struct drm_device *dev, long timeout); + +#define GET_URB_TIMEOUT HZ +static inline struct urb *udl_get_urb(struct drm_device *dev) +{ + return udl_get_urb_timeout(dev, GET_URB_TIMEOUT); +} int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len); +int udl_sync_pending_urbs(struct drm_device *dev); +void udl_kill_pending_urbs(struct drm_device *dev); void udl_urb_completion(struct urb *urb); int udl_init(struct udl_device *udl); diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c index 853f147036f6..fdafbf8f3c3c 100644 --- a/drivers/gpu/drm/udl/udl_main.c +++ b/drivers/gpu/drm/udl/udl_main.c @@ -23,9 +23,6 @@ #define WRITES_IN_FLIGHT (4) #define MAX_VENDOR_DESCRIPTOR_SIZE 256 -#define GET_URB_TIMEOUT HZ -#define FREE_URB_TIMEOUT (HZ*2) - static int udl_parse_vendor_descriptor(struct udl_device *udl) { struct usb_device *udev = udl_to_usb_device(udl); @@ -119,14 +116,6 @@ static int udl_select_std_channel(struct udl_device *udl) return ret < 0 ? ret : 0; } -static void udl_release_urb_work(struct work_struct *work) -{ - struct urb_node *unode = container_of(work, struct urb_node, - release_urb_work.work); - - up(&unode->dev->urbs.limit_sem); -} - void udl_urb_completion(struct urb *urb) { struct urb_node *unode = urb->context; @@ -146,27 +135,17 @@ void udl_urb_completion(struct urb *urb) urb->transfer_buffer_length = udl->urbs.size; /* reset to actual */ spin_lock_irqsave(&udl->urbs.lock, flags); - list_add_tail(&unode->entry, &udl->urbs.list); + list_move(&unode->entry, &udl->urbs.list); udl->urbs.available++; spin_unlock_irqrestore(&udl->urbs.lock, flags); -#if 0 - /* - * When using fb_defio, we deadlock if up() is called - * while another is waiting. So queue to another process. - */ - if (fb_defio) - schedule_delayed_work(&unode->release_urb_work, 0); - else -#endif - up(&udl->urbs.limit_sem); + wake_up(&udl->urbs.sleep); } static void udl_free_urb_list(struct drm_device *dev) { struct udl_device *udl = to_udl(dev); int count = udl->urbs.count; - struct list_head *node; struct urb_node *unode; struct urb *urb; @@ -174,23 +153,15 @@ static void udl_free_urb_list(struct drm_device *dev) /* keep waiting and freeing, until we've got 'em all */ while (count--) { - down(&udl->urbs.limit_sem); - - spin_lock_irq(&udl->urbs.lock); - - node = udl->urbs.list.next; /* have reserved one with sem */ - list_del_init(node); - - spin_unlock_irq(&udl->urbs.lock); - - unode = list_entry(node, struct urb_node, entry); - urb = unode->urb; - + urb = udl_get_urb_timeout(dev, MAX_SCHEDULE_TIMEOUT); + if (WARN_ON(!urb)) + break; + unode = urb->context; /* Free each separately allocated piece */ usb_free_coherent(urb->dev, udl->urbs.size, urb->transfer_buffer, urb->transfer_dma); usb_free_urb(urb); - kfree(node); + kfree(unode); } udl->urbs.count = 0; } @@ -209,8 +180,9 @@ static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size) retry: udl->urbs.size = size; INIT_LIST_HEAD(&udl->urbs.list); + INIT_LIST_HEAD(&udl->urbs.in_flight); - sema_init(&udl->urbs.limit_sem, 0); + init_waitqueue_head(&udl->urbs.sleep); udl->urbs.count = 0; udl->urbs.available = 0; @@ -220,9 +192,6 @@ retry: break; unode->dev = udl; - INIT_DELAYED_WORK(&unode->release_urb_work, - udl_release_urb_work); - urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) { kfree(unode); @@ -250,7 +219,6 @@ retry: list_add_tail(&unode->entry, &udl->urbs.list); - up(&udl->urbs.limit_sem); udl->urbs.count++; udl->urbs.available++; } @@ -260,36 +228,31 @@ retry: return udl->urbs.count; } -struct urb *udl_get_urb(struct drm_device *dev) +struct urb *udl_get_urb_timeout(struct drm_device *dev, long timeout) { struct udl_device *udl = to_udl(dev); - int ret = 0; - struct list_head *entry; - struct urb_node *unode; - struct urb *urb = NULL; + struct urb_node *unode = NULL; - /* Wait for an in-flight buffer to complete and get re-queued */ - ret = down_timeout(&udl->urbs.limit_sem, GET_URB_TIMEOUT); - if (ret) { - DRM_INFO("wait for urb interrupted: %x available: %d\n", - ret, udl->urbs.available); - goto error; - } + if (!udl->urbs.count) + return NULL; + /* Wait for an in-flight buffer to complete and get re-queued */ spin_lock_irq(&udl->urbs.lock); + if (!wait_event_lock_irq_timeout(udl->urbs.sleep, + !list_empty(&udl->urbs.list), + udl->urbs.lock, timeout)) { + DRM_INFO("wait for urb interrupted: available: %d\n", + udl->urbs.available); + goto unlock; + } - BUG_ON(list_empty(&udl->urbs.list)); /* reserved one with limit_sem */ - entry = udl->urbs.list.next; - list_del_init(entry); + unode = list_first_entry(&udl->urbs.list, struct urb_node, entry); + list_move(&unode->entry, &udl->urbs.in_flight); udl->urbs.available--; +unlock: spin_unlock_irq(&udl->urbs.lock); - - unode = list_entry(entry, struct urb_node, entry); - urb = unode->urb; - -error: - return urb; + return unode ? unode->urb : NULL; } int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len) @@ -297,7 +260,8 @@ int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len) struct udl_device *udl = to_udl(dev); int ret; - BUG_ON(len > udl->urbs.size); + if (WARN_ON(len > udl->urbs.size)) + return -EINVAL; urb->transfer_buffer_length = len; /* set to actual payload len */ ret = usb_submit_urb(urb, GFP_ATOMIC); @@ -308,6 +272,40 @@ int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len) return ret; } +/* wait until all pending URBs have been processed */ +int udl_sync_pending_urbs(struct drm_device *dev) +{ + struct udl_device *udl = to_udl(dev); + int ret = 0; + + spin_lock_irq(&udl->urbs.lock); + /* 2 seconds as a sane timeout */ + if (!wait_event_lock_irq_timeout(udl->urbs.sleep, + list_empty(&udl->urbs.in_flight), + udl->urbs.lock, + msecs_to_jiffies(2000))) + ret = -ETIMEDOUT; + spin_unlock_irq(&udl->urbs.lock); + return ret; +} + +/* kill pending URBs */ +void udl_kill_pending_urbs(struct drm_device *dev) +{ + struct udl_device *udl = to_udl(dev); + struct urb_node *unode; + + spin_lock_irq(&udl->urbs.lock); + while (!list_empty(&udl->urbs.in_flight)) { + unode = list_first_entry(&udl->urbs.in_flight, + struct urb_node, entry); + spin_unlock_irq(&udl->urbs.lock); + usb_kill_urb(unode->urb); + spin_lock_irq(&udl->urbs.lock); + } + spin_unlock_irq(&udl->urbs.lock); +} + int udl_init(struct udl_device *udl) { struct drm_device *dev = &udl->drm; @@ -356,6 +354,7 @@ int udl_drop_usb(struct drm_device *dev) { struct udl_device *udl = to_udl(dev); + udl_kill_pending_urbs(dev); udl_free_urb_list(dev); put_device(udl->dmadev); udl->dmadev = NULL; diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index e67c40a48fb4..169110d8fc2e 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -397,6 +397,8 @@ udl_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe) struct urb *urb; char *buf; + udl_kill_pending_urbs(dev); + urb = udl_get_urb(dev); if (!urb) return; @@ -408,6 +410,8 @@ udl_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe) buf = udl_dummy_render(buf); udl_submit_urb(dev, urb, buf - (char *)urb->transfer_buffer); + + udl_sync_pending_urbs(dev); } static void diff --git a/drivers/gpu/drm/udl/udl_transfer.c b/drivers/gpu/drm/udl/udl_transfer.c index 971927669d6b..176ef2a6a731 100644 --- a/drivers/gpu/drm/udl/udl_transfer.c +++ b/drivers/gpu/drm/udl/udl_transfer.c @@ -220,7 +220,8 @@ int udl_render_hline(struct drm_device *dev, int log_bpp, struct urb **urb_ptr, u8 *cmd = *urb_buf_ptr; u8 *cmd_end = (u8 *) urb->transfer_buffer + urb->transfer_buffer_length; - BUG_ON(!(log_bpp == 1 || log_bpp == 2)); + if (WARN_ON(!(log_bpp == 1 || log_bpp == 2))) + return -EINVAL; line_start = (u8 *) (front + byte_offset); next_pixel = line_start; diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c index 8c7f910daa28..e8c975b81585 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.c +++ b/drivers/gpu/drm/v3d/v3d_drv.c @@ -22,7 +22,6 @@ #include <linux/reset.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_managed.h> #include <uapi/drm/v3d_drm.h> diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index 725a252e837b..b8980440d137 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -313,7 +313,7 @@ v3d_lookup_bos(struct drm_device *dev, } job->bo = kvmalloc_array(job->bo_count, - sizeof(struct drm_gem_cma_object *), + sizeof(struct drm_gem_dma_object *), GFP_KERNEL | __GFP_ZERO); if (!job->bo) { DRM_DEBUG("Failed to allocate validated BO pointers\n"); @@ -1092,7 +1092,7 @@ v3d_gem_init(struct drm_device *dev) if (!v3d->pt) { drm_mm_takedown(&v3d->mm); dev_err(v3d->drm.dev, - "Failed to allocate page tables. Please ensure you have CMA enabled.\n"); + "Failed to allocate page tables. Please ensure you have DMA enabled.\n"); return -ENOMEM; } diff --git a/drivers/gpu/drm/v3d/v3d_perfmon.c b/drivers/gpu/drm/v3d/v3d_perfmon.c index f6a88abccc7d..48aaaa972c49 100644 --- a/drivers/gpu/drm/v3d/v3d_perfmon.c +++ b/drivers/gpu/drm/v3d/v3d_perfmon.c @@ -95,7 +95,7 @@ struct v3d_perfmon *v3d_perfmon_find(struct v3d_file_priv *v3d_priv, int id) void v3d_perfmon_open_file(struct v3d_file_priv *v3d_priv) { mutex_init(&v3d_priv->perfmon.lock); - idr_init(&v3d_priv->perfmon.idr); + idr_init_base(&v3d_priv->perfmon.idr, 1); } static int v3d_perfmon_idr_del(int id, void *elem, void *data) diff --git a/drivers/gpu/drm/vboxvideo/vbox_mode.c b/drivers/gpu/drm/vboxvideo/vbox_mode.c index fa0d73ce07bc..341edd982cb3 100644 --- a/drivers/gpu/drm/vboxvideo/vbox_mode.c +++ b/drivers/gpu/drm/vboxvideo/vbox_mode.c @@ -269,8 +269,8 @@ static int vbox_primary_atomic_check(struct drm_plane *plane, } return drm_atomic_helper_check_plane_state(new_state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, false, true); } @@ -351,8 +351,8 @@ static int vbox_cursor_atomic_check(struct drm_plane *plane, } ret = drm_atomic_helper_check_plane_state(new_state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, true, true); if (ret) return ret; @@ -477,7 +477,7 @@ static const struct drm_plane_helper_funcs vbox_cursor_helper_funcs = { static const struct drm_plane_funcs vbox_cursor_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, - .destroy = drm_primary_helper_destroy, + .destroy = drm_plane_helper_destroy, DRM_GEM_SHADOW_PLANE_FUNCS, }; @@ -496,7 +496,7 @@ static const struct drm_plane_helper_funcs vbox_primary_helper_funcs = { static const struct drm_plane_funcs vbox_primary_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, - .destroy = drm_primary_helper_destroy, + .destroy = drm_plane_helper_destroy, .reset = drm_atomic_helper_plane_reset, .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig index 061be9a6619d..246305d17a52 100644 --- a/drivers/gpu/drm/vc4/Kconfig +++ b/drivers/gpu/drm/vc4/Kconfig @@ -8,10 +8,11 @@ config DRM_VC4 depends on DRM depends on SND && SND_SOC depends on COMMON_CLK + depends on PM select DRM_DISPLAY_HDMI_HELPER select DRM_DISPLAY_HELPER select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_PANEL_BRIDGE select SND_PCM select SND_PCM_ELD diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c index 0846d56f74f2..231add8b8e12 100644 --- a/drivers/gpu/drm/vc4/vc4_bo.c +++ b/drivers/gpu/drm/vc4/vc4_bo.c @@ -8,10 +8,10 @@ * * The VC4 GPU architecture (both scanout and rendering) has direct * access to system memory with no MMU in between. To support it, we - * use the GEM CMA helper functions to allocate contiguous ranges of + * use the GEM DMA helper functions to allocate contiguous ranges of * physical memory for our BOs. * - * Since the CMA allocator is very slow, we keep a cache of recently + * Since the DMA allocator is very slow, we keep a cache of recently * freed BOs around so that the kernel's allocation of objects for 3D * rendering can return quickly. */ @@ -179,7 +179,7 @@ static void vc4_bo_destroy(struct vc4_bo *bo) bo->validated_shader = NULL; } - drm_gem_cma_free(&bo->base); + drm_gem_dma_free(&bo->base); } static void vc4_bo_remove_from_cache(struct vc4_bo *bo) @@ -303,7 +303,7 @@ static void vc4_bo_purge(struct drm_gem_object *obj) drm_vma_node_unmap(&obj->vma_node, dev->anon_inode->i_mapping); - dma_free_wc(dev->dev, obj->size, bo->base.vaddr, bo->base.paddr); + dma_free_wc(dev->dev, obj->size, bo->base.vaddr, bo->base.dma_addr); bo->base.vaddr = NULL; bo->madv = __VC4_MADV_PURGED; } @@ -387,13 +387,14 @@ out: * @dev: DRM device * @size: Size in bytes of the memory the object will reference * - * This lets the CMA helpers allocate object structs for us, and keep + * This lets the DMA helpers allocate object structs for us, and keep * our BO stats correct. */ struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size) { struct vc4_dev *vc4 = to_vc4_dev(dev); struct vc4_bo *bo; + int ret; if (WARN_ON_ONCE(vc4->is_vc5)) return ERR_PTR(-ENODEV); @@ -404,7 +405,11 @@ struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size) bo->madv = VC4_MADV_WILLNEED; refcount_set(&bo->usecnt, 0); - mutex_init(&bo->madv_lock); + + ret = drmm_mutex_init(dev, &bo->madv_lock); + if (ret) + return ERR_PTR(ret); + mutex_lock(&vc4->bo_lock); bo->label = VC4_BO_TYPE_KERNEL; vc4->bo_labels[VC4_BO_TYPE_KERNEL].num_allocated++; @@ -421,7 +426,7 @@ struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size, { size_t size = roundup(unaligned_size, PAGE_SIZE); struct vc4_dev *vc4 = to_vc4_dev(dev); - struct drm_gem_cma_object *cma_obj; + struct drm_gem_dma_object *dma_obj; struct vc4_bo *bo; if (WARN_ON_ONCE(vc4->is_vc5)) @@ -438,39 +443,39 @@ struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size, return bo; } - cma_obj = drm_gem_cma_create(dev, size); - if (IS_ERR(cma_obj)) { + dma_obj = drm_gem_dma_create(dev, size); + if (IS_ERR(dma_obj)) { /* - * If we've run out of CMA memory, kill the cache of - * CMA allocations we've got laying around and try again. + * If we've run out of DMA memory, kill the cache of + * DMA allocations we've got laying around and try again. */ vc4_bo_cache_purge(dev); - cma_obj = drm_gem_cma_create(dev, size); + dma_obj = drm_gem_dma_create(dev, size); } - if (IS_ERR(cma_obj)) { + if (IS_ERR(dma_obj)) { /* - * Still not enough CMA memory, purge the userspace BO + * Still not enough DMA memory, purge the userspace BO * cache and retry. * This is sub-optimal since we purge the whole userspace * BO cache which forces user that want to re-use the BO to * restore its initial content. * Ideally, we should purge entries one by one and retry - * after each to see if CMA allocation succeeds. Or even + * after each to see if DMA allocation succeeds. Or even * better, try to find an entry with at least the same * size. */ vc4_bo_userspace_cache_purge(dev); - cma_obj = drm_gem_cma_create(dev, size); + dma_obj = drm_gem_dma_create(dev, size); } - if (IS_ERR(cma_obj)) { + if (IS_ERR(dma_obj)) { struct drm_printer p = drm_info_printer(vc4->base.dev); - DRM_ERROR("Failed to allocate from CMA:\n"); + DRM_ERROR("Failed to allocate from GEM DMA helper:\n"); vc4_bo_stats_print(&p, vc4); return ERR_PTR(-ENOMEM); } - bo = to_vc4_bo(&cma_obj->base); + bo = to_vc4_bo(&dma_obj->base); /* By default, BOs do not support the MADV ioctl. This will be enabled * only on BOs that are exposed to userspace (V3D, V3D_SHADER and DUMB @@ -479,7 +484,7 @@ struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size, bo->madv = __VC4_MADV_NOTSUPP; mutex_lock(&vc4->bo_lock); - vc4_bo_set_label(&cma_obj->base, type); + vc4_bo_set_label(&dma_obj->base, type); mutex_unlock(&vc4->bo_lock); return bo; @@ -564,7 +569,7 @@ static void vc4_free_object(struct drm_gem_object *gem_bo) goto out; } - /* If this object was partially constructed but CMA allocation + /* If this object was partially constructed but DMA allocation * had failed, just free it. Can also happen when the BO has been * purged. */ @@ -742,7 +747,7 @@ static int vc4_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct return -EINVAL; } - return drm_gem_cma_mmap(&bo->base, vma); + return drm_gem_dma_mmap(&bo->base, vma); } static const struct vm_operations_struct vc4_vm_ops = { @@ -754,8 +759,8 @@ static const struct vm_operations_struct vc4_vm_ops = { static const struct drm_gem_object_funcs vc4_gem_object_funcs = { .free = vc4_free_object, .export = vc4_prime_export, - .get_sg_table = drm_gem_cma_object_get_sg_table, - .vmap = drm_gem_cma_object_vmap, + .get_sg_table = drm_gem_dma_object_get_sg_table, + .vmap = drm_gem_dma_object_vmap, .mmap = vc4_gem_object_mmap, .vm_ops = &vc4_vm_ops, }; @@ -984,10 +989,28 @@ int vc4_get_tiling_ioctl(struct drm_device *dev, void *data, return 0; } +int vc4_bo_debugfs_init(struct drm_minor *minor) +{ + struct drm_device *drm = minor->dev; + struct vc4_dev *vc4 = to_vc4_dev(drm); + int ret; + + if (!vc4->v3d) + return -ENODEV; + + ret = vc4_debugfs_add_file(minor, "bo_stats", + vc4_bo_stats_debugfs, NULL); + if (ret) + return ret; + + return 0; +} + static void vc4_bo_cache_destroy(struct drm_device *dev, void *unused); int vc4_bo_cache_init(struct drm_device *dev) { struct vc4_dev *vc4 = to_vc4_dev(dev); + int ret; int i; if (WARN_ON_ONCE(vc4->is_vc5)) @@ -1007,9 +1030,11 @@ int vc4_bo_cache_init(struct drm_device *dev) for (i = 0; i < VC4_BO_TYPE_COUNT; i++) vc4->bo_labels[i].name = bo_type_names[i]; - mutex_init(&vc4->bo_lock); - - vc4_debugfs_add_file(dev, "bo_stats", vc4_bo_stats_debugfs, NULL); + ret = drmm_mutex_init(dev, &vc4->bo_lock); + if (ret) { + kfree(vc4->bo_labels); + return ret; + } INIT_LIST_HEAD(&vc4->bo_cache.time_list); diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 029be98660b3..2def6e2ad6f0 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -37,7 +37,7 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_uapi.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_framebuffer.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> @@ -206,11 +206,6 @@ static bool vc4_crtc_get_scanout_position(struct drm_crtc *crtc, return ret; } -void vc4_crtc_destroy(struct drm_crtc *crtc) -{ - drm_crtc_cleanup(crtc); -} - static u32 vc4_get_fifo_full_level(struct vc4_crtc *vc4_crtc, u32 format) { const struct vc4_crtc_data *crtc_data = vc4_crtc_to_vc4_crtc_data(vc4_crtc); @@ -544,6 +539,20 @@ int vc4_crtc_disable_at_boot(struct drm_crtc *crtc) return 0; } +void vc4_crtc_send_vblank(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + unsigned long flags; + + if (!crtc->state || !crtc->state->event) + return; + + spin_lock_irqsave(&dev->event_lock, flags); + drm_crtc_send_vblank_event(crtc, crtc->state->event); + crtc->state->event = NULL; + spin_unlock_irqrestore(&dev->event_lock, flags); +} + static void vc4_crtc_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state) { @@ -567,14 +576,7 @@ static void vc4_crtc_atomic_disable(struct drm_crtc *crtc, * Make sure we issue a vblank event after disabling the CRTC if * someone was waiting it. */ - if (crtc->state->event) { - unsigned long flags; - - spin_lock_irqsave(&dev->event_lock, flags); - drm_crtc_send_vblank_event(crtc, crtc->state->event); - crtc->state->event = NULL; - spin_unlock_irqrestore(&dev->event_lock, flags); - } + vc4_crtc_send_vblank(crtc); } static void vc4_crtc_atomic_enable(struct drm_crtc *crtc, @@ -821,9 +823,9 @@ static void vc4_async_page_flip_seqno_complete(struct vc4_seqno_cb *cb) struct vc4_bo *bo = NULL; if (flip_state->old_fb) { - struct drm_gem_cma_object *cma_bo = - drm_fb_cma_get_gem_obj(flip_state->old_fb, 0); - bo = to_vc4_bo(&cma_bo->base); + struct drm_gem_dma_object *dma_bo = + drm_fb_dma_get_gem_obj(flip_state->old_fb, 0); + bo = to_vc4_bo(&dma_bo->base); } vc4_async_page_flip_complete(flip_state); @@ -855,19 +857,19 @@ static int vc4_async_set_fence_cb(struct drm_device *dev, struct vc4_async_flip_state *flip_state) { struct drm_framebuffer *fb = flip_state->fb; - struct drm_gem_cma_object *cma_bo = drm_fb_cma_get_gem_obj(fb, 0); + struct drm_gem_dma_object *dma_bo = drm_fb_dma_get_gem_obj(fb, 0); struct vc4_dev *vc4 = to_vc4_dev(dev); struct dma_fence *fence; int ret; if (!vc4->is_vc5) { - struct vc4_bo *bo = to_vc4_bo(&cma_bo->base); + struct vc4_bo *bo = to_vc4_bo(&dma_bo->base); return vc4_queue_seqno_cb(dev, &flip_state->cb.seqno, bo->seqno, vc4_async_page_flip_seqno_complete); } - ret = dma_resv_get_singleton(cma_bo->base.resv, DMA_RESV_USAGE_READ, &fence); + ret = dma_resv_get_singleton(dma_bo->base.resv, DMA_RESV_USAGE_READ, &fence); if (ret) return ret; @@ -943,8 +945,8 @@ static int vc4_async_page_flip(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; struct vc4_dev *vc4 = to_vc4_dev(dev); - struct drm_gem_cma_object *cma_bo = drm_fb_cma_get_gem_obj(fb, 0); - struct vc4_bo *bo = to_vc4_bo(&cma_bo->base); + struct drm_gem_dma_object *dma_bo = drm_fb_dma_get_gem_obj(fb, 0); + struct vc4_bo *bo = to_vc4_bo(&dma_bo->base); int ret; if (WARN_ON_ONCE(vc4->is_vc5)) @@ -1050,9 +1052,23 @@ void vc4_crtc_reset(struct drm_crtc *crtc) __drm_atomic_helper_crtc_reset(crtc, &vc4_crtc_state->base); } +int vc4_crtc_late_register(struct drm_crtc *crtc) +{ + struct drm_device *drm = crtc->dev; + struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); + const struct vc4_crtc_data *crtc_data = vc4_crtc_to_vc4_crtc_data(vc4_crtc); + int ret; + + ret = vc4_debugfs_add_regset32(drm->primary, crtc_data->debugfs_name, + &vc4_crtc->regset); + if (ret) + return ret; + + return 0; +} + static const struct drm_crtc_funcs vc4_crtc_funcs = { .set_config = drm_atomic_helper_set_config, - .destroy = vc4_crtc_destroy, .page_flip = vc4_page_flip, .set_property = NULL, .cursor_set = NULL, /* handled by drm_mode_cursor_universal */ @@ -1063,6 +1079,7 @@ static const struct drm_crtc_funcs vc4_crtc_funcs = { .enable_vblank = vc4_enable_vblank, .disable_vblank = vc4_disable_vblank, .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp, + .late_register = vc4_crtc_late_register, }; static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = { @@ -1077,10 +1094,10 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = { static const struct vc4_pv_data bcm2835_pv0_data = { .base = { + .debugfs_name = "crtc0_regs", .hvs_available_channels = BIT(0), .hvs_output = 0, }, - .debugfs_name = "crtc0_regs", .fifo_depth = 64, .pixels_per_clock = 1, .encoder_types = { @@ -1091,10 +1108,10 @@ static const struct vc4_pv_data bcm2835_pv0_data = { static const struct vc4_pv_data bcm2835_pv1_data = { .base = { + .debugfs_name = "crtc1_regs", .hvs_available_channels = BIT(2), .hvs_output = 2, }, - .debugfs_name = "crtc1_regs", .fifo_depth = 64, .pixels_per_clock = 1, .encoder_types = { @@ -1105,10 +1122,10 @@ static const struct vc4_pv_data bcm2835_pv1_data = { static const struct vc4_pv_data bcm2835_pv2_data = { .base = { + .debugfs_name = "crtc2_regs", .hvs_available_channels = BIT(1), .hvs_output = 1, }, - .debugfs_name = "crtc2_regs", .fifo_depth = 64, .pixels_per_clock = 1, .encoder_types = { @@ -1119,10 +1136,10 @@ static const struct vc4_pv_data bcm2835_pv2_data = { static const struct vc4_pv_data bcm2711_pv0_data = { .base = { + .debugfs_name = "crtc0_regs", .hvs_available_channels = BIT(0), .hvs_output = 0, }, - .debugfs_name = "crtc0_regs", .fifo_depth = 64, .pixels_per_clock = 1, .encoder_types = { @@ -1133,10 +1150,10 @@ static const struct vc4_pv_data bcm2711_pv0_data = { static const struct vc4_pv_data bcm2711_pv1_data = { .base = { + .debugfs_name = "crtc1_regs", .hvs_available_channels = BIT(0) | BIT(1) | BIT(2), .hvs_output = 3, }, - .debugfs_name = "crtc1_regs", .fifo_depth = 64, .pixels_per_clock = 1, .encoder_types = { @@ -1147,10 +1164,10 @@ static const struct vc4_pv_data bcm2711_pv1_data = { static const struct vc4_pv_data bcm2711_pv2_data = { .base = { + .debugfs_name = "crtc2_regs", .hvs_available_channels = BIT(0) | BIT(1) | BIT(2), .hvs_output = 4, }, - .debugfs_name = "crtc2_regs", .fifo_depth = 256, .pixels_per_clock = 2, .encoder_types = { @@ -1160,10 +1177,10 @@ static const struct vc4_pv_data bcm2711_pv2_data = { static const struct vc4_pv_data bcm2711_pv3_data = { .base = { + .debugfs_name = "crtc3_regs", .hvs_available_channels = BIT(1), .hvs_output = 1, }, - .debugfs_name = "crtc3_regs", .fifo_depth = 64, .pixels_per_clock = 1, .encoder_types = { @@ -1173,10 +1190,10 @@ static const struct vc4_pv_data bcm2711_pv3_data = { static const struct vc4_pv_data bcm2711_pv4_data = { .base = { + .debugfs_name = "crtc4_regs", .hvs_available_channels = BIT(0) | BIT(1) | BIT(2), .hvs_output = 5, }, - .debugfs_name = "crtc4_regs", .fifo_depth = 64, .pixels_per_clock = 2, .encoder_types = { @@ -1230,6 +1247,7 @@ int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc, struct drm_crtc *crtc = &vc4_crtc->base; struct drm_plane *primary_plane; unsigned int i; + int ret; /* For now, we create just the primary and the legacy cursor * planes. We should be able to stack more planes on easily, @@ -1237,15 +1255,18 @@ int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc, * requirement of the plane configuration, and reject ones * that will take too much. */ - primary_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_PRIMARY); + primary_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_PRIMARY, 0); if (IS_ERR(primary_plane)) { dev_err(drm->dev, "failed to construct primary plane\n"); return PTR_ERR(primary_plane); } spin_lock_init(&vc4_crtc->irq_lock); - drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL, - crtc_funcs, NULL); + ret = drmm_crtc_init_with_planes(drm, crtc, primary_plane, NULL, + crtc_funcs, NULL); + if (ret) + return ret; + drm_crtc_helper_add(crtc, crtc_helper_funcs); if (!vc4->is_vc5) { @@ -1275,10 +1296,9 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data) const struct vc4_pv_data *pv_data; struct vc4_crtc *vc4_crtc; struct drm_crtc *crtc; - struct drm_plane *destroy_plane, *temp; int ret; - vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL); + vc4_crtc = drmm_kzalloc(drm, sizeof(*vc4_crtc), GFP_KERNEL); if (!vc4_crtc) return -ENOMEM; crtc = &vc4_crtc->base; @@ -1310,23 +1330,11 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data) IRQF_SHARED, "vc4 crtc", vc4_crtc); if (ret) - goto err_destroy_planes; + return ret; platform_set_drvdata(pdev, vc4_crtc); - vc4_debugfs_add_regset32(drm, pv_data->debugfs_name, - &vc4_crtc->regset); - return 0; - -err_destroy_planes: - list_for_each_entry_safe(destroy_plane, temp, - &drm->mode_config.plane_list, head) { - if (destroy_plane->possible_crtcs == drm_crtc_mask(crtc)) - destroy_plane->funcs->destroy(destroy_plane); - } - - return ret; } static void vc4_crtc_unbind(struct device *dev, struct device *master, @@ -1335,8 +1343,6 @@ static void vc4_crtc_unbind(struct device *dev, struct device *master, struct platform_device *pdev = to_platform_device(dev); struct vc4_crtc *vc4_crtc = dev_get_drvdata(dev); - vc4_crtc_destroy(&vc4_crtc->base); - CRTC_WRITE(PV_INTEN, 0); platform_set_drvdata(pdev, NULL); diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c index ba2d8ea562af..19cda4f91a82 100644 --- a/drivers/gpu/drm/vc4/vc4_debugfs.c +++ b/drivers/gpu/drm/vc4/vc4_debugfs.c @@ -3,6 +3,8 @@ * Copyright © 2014 Broadcom */ +#include <drm/drm_drv.h> + #include <linux/seq_file.h> #include <linux/circ_buf.h> #include <linux/ctype.h> @@ -12,11 +14,6 @@ #include "vc4_drv.h" #include "vc4_regs.h" -struct vc4_debugfs_info_entry { - struct list_head link; - struct drm_info_list info; -}; - /* * Called at drm_dev_register() time on each of the minors registered * by the DRM device, to attach the debugfs files. @@ -25,62 +22,59 @@ void vc4_debugfs_init(struct drm_minor *minor) { struct vc4_dev *vc4 = to_vc4_dev(minor->dev); - struct vc4_debugfs_info_entry *entry; + struct drm_device *drm = &vc4->base; - if (!of_device_is_compatible(vc4->hvs->pdev->dev.of_node, - "brcm,bcm2711-vc5")) - debugfs_create_bool("hvs_load_tracker", S_IRUGO | S_IWUSR, - minor->debugfs_root, &vc4->load_tracker_enabled); + drm_WARN_ON(drm, vc4_hvs_debugfs_init(minor)); - list_for_each_entry(entry, &vc4->debugfs_list, link) { - drm_debugfs_create_files(&entry->info, 1, - minor->debugfs_root, minor); + if (vc4->v3d) { + drm_WARN_ON(drm, vc4_bo_debugfs_init(minor)); + drm_WARN_ON(drm, vc4_v3d_debugfs_init(minor)); } } static int vc4_debugfs_regset32(struct seq_file *m, void *unused) { struct drm_info_node *node = (struct drm_info_node *)m->private; + struct drm_device *drm = node->minor->dev; struct debugfs_regset32 *regset = node->info_ent->data; struct drm_printer p = drm_seq_file_printer(m); + int idx; + + if (!drm_dev_enter(drm, &idx)) + return -ENODEV; drm_print_regset32(&p, regset); + drm_dev_exit(idx); + return 0; } -/* - * Registers a debugfs file with a callback function for a vc4 component. - * - * This is like drm_debugfs_create_files(), but that can only be - * called a given DRM minor, while the various VC4 components want to - * register their debugfs files during the component bind process. We - * track the request and delay it to be called on each minor during - * vc4_debugfs_init(). - */ -void vc4_debugfs_add_file(struct drm_device *dev, - const char *name, - int (*show)(struct seq_file*, void*), - void *data) +int vc4_debugfs_add_file(struct drm_minor *minor, + const char *name, + int (*show)(struct seq_file*, void*), + void *data) { - struct vc4_dev *vc4 = to_vc4_dev(dev); + struct drm_device *dev = minor->dev; + struct dentry *root = minor->debugfs_root; + struct drm_info_list *file; - struct vc4_debugfs_info_entry *entry = - devm_kzalloc(dev->dev, sizeof(*entry), GFP_KERNEL); + file = drmm_kzalloc(dev, sizeof(*file), GFP_KERNEL); + if (!file) + return -ENOMEM; - if (!entry) - return; + file->name = name; + file->show = show; + file->data = data; - entry->info.name = name; - entry->info.show = show; - entry->info.data = data; + drm_debugfs_create_files(file, 1, root, minor); - list_add(&entry->link, &vc4->debugfs_list); + return 0; } -void vc4_debugfs_add_regset32(struct drm_device *drm, - const char *name, - struct debugfs_regset32 *regset) +int vc4_debugfs_add_regset32(struct drm_minor *minor, + const char *name, + struct debugfs_regset32 *regset) { - vc4_debugfs_add_file(drm, name, vc4_debugfs_regset32, regset); + return vc4_debugfs_add_file(minor, name, vc4_debugfs_regset32, regset); } diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c index ef5e3921062c..1f8f44b7b5a5 100644 --- a/drivers/gpu/drm/vc4/vc4_dpi.c +++ b/drivers/gpu/drm/vc4/vc4_dpi.c @@ -13,6 +13,7 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> +#include <drm/drm_drv.h> #include <drm/drm_edid.h> #include <drm/drm_of.h> #include <drm/drm_panel.h> @@ -84,9 +85,9 @@ /* General DPI hardware state. */ struct vc4_dpi { - struct platform_device *pdev; + struct vc4_encoder encoder; - struct drm_encoder *encoder; + struct platform_device *pdev; void __iomem *regs; @@ -96,21 +97,15 @@ struct vc4_dpi { struct debugfs_regset32 regset; }; -#define DPI_READ(offset) readl(dpi->regs + (offset)) -#define DPI_WRITE(offset, val) writel(val, dpi->regs + (offset)) - -/* VC4 DPI encoder KMS struct */ -struct vc4_dpi_encoder { - struct vc4_encoder base; - struct vc4_dpi *dpi; -}; - -static inline struct vc4_dpi_encoder * -to_vc4_dpi_encoder(struct drm_encoder *encoder) +static inline struct vc4_dpi * +to_vc4_dpi(struct drm_encoder *encoder) { - return container_of(encoder, struct vc4_dpi_encoder, base.base); + return container_of(encoder, struct vc4_dpi, encoder.base); } +#define DPI_READ(offset) readl(dpi->regs + (offset)) +#define DPI_WRITE(offset, val) writel(val, dpi->regs + (offset)) + static const struct debugfs_reg32 dpi_regs[] = { VC4_REG32(DPI_C), VC4_REG32(DPI_ID), @@ -118,21 +113,27 @@ static const struct debugfs_reg32 dpi_regs[] = { static void vc4_dpi_encoder_disable(struct drm_encoder *encoder) { - struct vc4_dpi_encoder *vc4_encoder = to_vc4_dpi_encoder(encoder); - struct vc4_dpi *dpi = vc4_encoder->dpi; + struct drm_device *dev = encoder->dev; + struct vc4_dpi *dpi = to_vc4_dpi(encoder); + int idx; + + if (!drm_dev_enter(dev, &idx)) + return; clk_disable_unprepare(dpi->pixel_clock); + + drm_dev_exit(idx); } static void vc4_dpi_encoder_enable(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct drm_display_mode *mode = &encoder->crtc->mode; - struct vc4_dpi_encoder *vc4_encoder = to_vc4_dpi_encoder(encoder); - struct vc4_dpi *dpi = vc4_encoder->dpi; + struct vc4_dpi *dpi = to_vc4_dpi(encoder); struct drm_connector_list_iter conn_iter; struct drm_connector *connector = NULL, *connector_scan; u32 dpi_c = DPI_ENABLE; + int idx; int ret; /* Look up the connector attached to DPI so we can get the @@ -212,6 +213,9 @@ static void vc4_dpi_encoder_enable(struct drm_encoder *encoder) dpi_c |= DPI_VSYNC_DISABLE; } + if (!drm_dev_enter(dev, &idx)) + return; + DPI_WRITE(DPI_C, dpi_c); ret = clk_set_rate(dpi->pixel_clock, mode->clock * 1000); @@ -221,6 +225,8 @@ static void vc4_dpi_encoder_enable(struct drm_encoder *encoder) ret = clk_prepare_enable(dpi->pixel_clock); if (ret) DRM_ERROR("Failed to set clock rate: %d\n", ret); + + drm_dev_exit(idx); } static enum drm_mode_status vc4_dpi_encoder_mode_valid(struct drm_encoder *encoder, @@ -238,6 +244,23 @@ static const struct drm_encoder_helper_funcs vc4_dpi_encoder_helper_funcs = { .mode_valid = vc4_dpi_encoder_mode_valid, }; +static int vc4_dpi_late_register(struct drm_encoder *encoder) +{ + struct drm_device *drm = encoder->dev; + struct vc4_dpi *dpi = to_vc4_dpi(encoder); + int ret; + + ret = vc4_debugfs_add_regset32(drm->primary, "dpi_regs", &dpi->regset); + if (ret) + return ret; + + return 0; +} + +static const struct drm_encoder_funcs vc4_dpi_encoder_funcs = { + .late_register = vc4_dpi_late_register, +}; + static const struct of_device_id vc4_dpi_dt_match[] = { { .compatible = "brcm,bcm2835-dpi", .data = NULL }, {} @@ -248,10 +271,11 @@ static const struct of_device_id vc4_dpi_dt_match[] = { */ static int vc4_dpi_init_bridge(struct vc4_dpi *dpi) { + struct drm_device *drm = dpi->encoder.base.dev; struct device *dev = &dpi->pdev->dev; struct drm_bridge *bridge; - bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0); + bridge = drmm_of_get_bridge(drm, dev->of_node, 0, 0); if (IS_ERR(bridge)) { /* If nothing was connected in the DT, that's not an * error. @@ -262,30 +286,28 @@ static int vc4_dpi_init_bridge(struct vc4_dpi *dpi) return PTR_ERR(bridge); } - return drm_bridge_attach(dpi->encoder, bridge, NULL, 0); + return drm_bridge_attach(&dpi->encoder.base, bridge, NULL, 0); +} + +static void vc4_dpi_disable_clock(void *ptr) +{ + struct vc4_dpi *dpi = ptr; + + clk_disable_unprepare(dpi->core_clock); } static int vc4_dpi_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); struct drm_device *drm = dev_get_drvdata(master); - struct vc4_dev *vc4 = to_vc4_dev(drm); struct vc4_dpi *dpi; - struct vc4_dpi_encoder *vc4_dpi_encoder; int ret; - dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL); + dpi = drmm_kzalloc(drm, sizeof(*dpi), GFP_KERNEL); if (!dpi) return -ENOMEM; - vc4_dpi_encoder = devm_kzalloc(dev, sizeof(*vc4_dpi_encoder), - GFP_KERNEL); - if (!vc4_dpi_encoder) - return -ENOMEM; - vc4_dpi_encoder->base.type = VC4_ENCODER_TYPE_DPI; - vc4_dpi_encoder->dpi = dpi; - dpi->encoder = &vc4_dpi_encoder->base.base; - + dpi->encoder.type = VC4_ENCODER_TYPE_DPI; dpi->pdev = pdev; dpi->regs = vc4_ioremap_regs(pdev, 0); if (IS_ERR(dpi->regs)) @@ -307,6 +329,7 @@ static int vc4_dpi_bind(struct device *dev, struct device *master, void *data) DRM_ERROR("Failed to get core clock: %d\n", ret); return ret; } + dpi->pixel_clock = devm_clk_get(dev, "pixel"); if (IS_ERR(dpi->pixel_clock)) { ret = PTR_ERR(dpi->pixel_clock); @@ -316,49 +339,35 @@ static int vc4_dpi_bind(struct device *dev, struct device *master, void *data) } ret = clk_prepare_enable(dpi->core_clock); - if (ret) + if (ret) { DRM_ERROR("Failed to turn on core clock: %d\n", ret); + return ret; + } - drm_simple_encoder_init(drm, dpi->encoder, DRM_MODE_ENCODER_DPI); - drm_encoder_helper_add(dpi->encoder, &vc4_dpi_encoder_helper_funcs); + ret = devm_add_action_or_reset(dev, vc4_dpi_disable_clock, dpi); + if (ret) + return ret; - ret = vc4_dpi_init_bridge(dpi); + ret = drmm_encoder_init(drm, &dpi->encoder.base, + &vc4_dpi_encoder_funcs, + DRM_MODE_ENCODER_DPI, + NULL); if (ret) - goto err_destroy_encoder; + return ret; - dev_set_drvdata(dev, dpi); + drm_encoder_helper_add(&dpi->encoder.base, &vc4_dpi_encoder_helper_funcs); - vc4->dpi = dpi; + ret = vc4_dpi_init_bridge(dpi); + if (ret) + return ret; - vc4_debugfs_add_regset32(drm, "dpi_regs", &dpi->regset); + dev_set_drvdata(dev, dpi); return 0; - -err_destroy_encoder: - drm_encoder_cleanup(dpi->encoder); - clk_disable_unprepare(dpi->core_clock); - return ret; -} - -static void vc4_dpi_unbind(struct device *dev, struct device *master, - void *data) -{ - struct drm_device *drm = dev_get_drvdata(master); - struct vc4_dev *vc4 = to_vc4_dev(drm); - struct vc4_dpi *dpi = dev_get_drvdata(dev); - - drm_of_panel_bridge_remove(dev->of_node, 0, 0); - - drm_encoder_cleanup(dpi->encoder); - - clk_disable_unprepare(dpi->core_clock); - - vc4->dpi = NULL; } static const struct component_ops vc4_dpi_ops = { .bind = vc4_dpi_bind, - .unbind = vc4_dpi_unbind, }; static int vc4_dpi_dev_probe(struct platform_device *pdev) diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index 292d1b6a01b6..ffbbb454c9e8 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -33,7 +33,6 @@ #include <drm/drm_aperture.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_vblank.h> @@ -86,7 +85,7 @@ static int vc5_dumb_create(struct drm_file *file_priv, if (ret) return ret; - return drm_gem_cma_dumb_create_internal(file_priv, dev, args); + return drm_gem_dma_dumb_create_internal(file_priv, dev, args); } static int vc4_get_param_ioctl(struct drm_device *dev, void *data, @@ -212,7 +211,7 @@ static const struct drm_driver vc4_drm_driver = { .gem_create_object = vc4_create_object, - DRM_GEM_CMA_DRIVER_OPS_WITH_DUMB_CREATE(vc4_bo_dumb_create), + DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(vc4_bo_dumb_create), .ioctls = vc4_drm_ioctls, .num_ioctls = ARRAY_SIZE(vc4_drm_ioctls), @@ -235,7 +234,7 @@ static const struct drm_driver vc5_drm_driver = { .debugfs_init = vc4_debugfs_init, #endif - DRM_GEM_CMA_DRIVER_OPS_WITH_DUMB_CREATE(vc5_dumb_create), + DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(vc5_dumb_create), .fops = &vc4_drm_fops, @@ -267,6 +266,13 @@ static void vc4_match_add_drivers(struct device *dev, } } +static void vc4_component_unbind_all(void *ptr) +{ + struct vc4_dev *vc4 = ptr; + + component_unbind_all(vc4->dev, &vc4->base); +} + static const struct of_device_id vc4_dma_range_matches[] = { { .compatible = "brcm,bcm2711-hvs" }, { .compatible = "brcm,bcm2835-hvs" }, @@ -310,13 +316,16 @@ static int vc4_drm_bind(struct device *dev) if (IS_ERR(vc4)) return PTR_ERR(vc4); vc4->is_vc5 = is_vc5; + vc4->dev = dev; drm = &vc4->base; platform_set_drvdata(pdev, drm); INIT_LIST_HEAD(&vc4->debugfs_list); if (!is_vc5) { - mutex_init(&vc4->bin_bo_lock); + ret = drmm_mutex_init(drm, &vc4->bin_bo_lock); + if (ret) + return ret; ret = vc4_bo_cache_init(drm); if (ret) @@ -360,6 +369,10 @@ static int vc4_drm_bind(struct device *dev) if (ret) return ret; + ret = devm_add_action_or_reset(dev, vc4_component_unbind_all, vc4); + if (ret) + return ret; + ret = vc4_plane_create_additional_planes(drm); if (ret) goto unbind_all; @@ -380,8 +393,6 @@ static int vc4_drm_bind(struct device *dev) return 0; unbind_all: - component_unbind_all(dev, drm); - return ret; } @@ -389,8 +400,7 @@ static void vc4_drm_unbind(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); - drm_dev_unregister(drm); - + drm_dev_unplug(drm); drm_atomic_helper_shutdown(drm); } diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 1beb96b77b8c..418a8242691f 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -14,7 +14,7 @@ #include <drm/drm_debugfs.h> #include <drm/drm_device.h> #include <drm/drm_encoder.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_managed.h> #include <drm/drm_mm.h> #include <drm/drm_modeset_lock.h> @@ -76,6 +76,7 @@ struct vc4_perfmon { struct vc4_dev { struct drm_device base; + struct device *dev; bool is_vc5; @@ -83,9 +84,6 @@ struct vc4_dev { struct vc4_hvs *hvs; struct vc4_v3d *v3d; - struct vc4_dpi *dpi; - struct vc4_vec *vec; - struct vc4_txp *txp; struct vc4_hang_state *hang_state; @@ -241,7 +239,7 @@ to_vc4_dev(struct drm_device *dev) } struct vc4_bo { - struct drm_gem_cma_object base; + struct drm_gem_dma_object base; /* seqno of the last job to render using this BO. */ uint64_t seqno; @@ -290,7 +288,7 @@ struct vc4_bo { static inline struct vc4_bo * to_vc4_bo(struct drm_gem_object *bo) { - return container_of(to_drm_gem_cma_obj(bo), struct vc4_bo, base); + return container_of(to_drm_gem_dma_obj(bo), struct vc4_bo, base); } struct vc4_fence { @@ -458,6 +456,8 @@ to_vc4_encoder(struct drm_encoder *encoder) } struct vc4_crtc_data { + const char *debugfs_name; + /* Bitmask of channels (FIFOs) of the HVS that the output can source from */ unsigned int hvs_available_channels; @@ -475,8 +475,6 @@ struct vc4_pv_data { u8 pixels_per_clock; enum vc4_encoder_type encoder_types[4]; - const char *debugfs_name; - }; struct vc4_crtc { @@ -604,14 +602,14 @@ struct vc4_exec_info { /* This is the array of BOs that were looked up at the start of exec. * Command validation will use indices into this array. */ - struct drm_gem_cma_object **bo; + struct drm_gem_dma_object **bo; uint32_t bo_count; /* List of BOs that are being written by the RCL. Other than * the binner temporary storage, this is all the BOs written * by the job. */ - struct drm_gem_cma_object *rcl_write_bo[4]; + struct drm_gem_dma_object *rcl_write_bo[4]; uint32_t rcl_write_bo_count; /* Pointers for our position in vc4->job_list */ @@ -630,7 +628,7 @@ struct vc4_exec_info { /* This is the BO where we store the validated command lists, shader * records, and uniforms. */ - struct drm_gem_cma_object *exec_bo; + struct drm_gem_dma_object *exec_bo; /** * This tracks the per-shader-record state (packet 64) that @@ -843,6 +841,7 @@ int vc4_bo_inc_usecnt(struct vc4_bo *bo); void vc4_bo_dec_usecnt(struct vc4_bo *bo); void vc4_bo_add_to_purgeable_pool(struct vc4_bo *bo); void vc4_bo_remove_from_purgeable_pool(struct vc4_bo *bo); +int vc4_bo_debugfs_init(struct drm_minor *minor); /* vc4_crtc.c */ extern struct platform_driver vc4_crtc_driver; @@ -850,7 +849,6 @@ int vc4_crtc_disable_at_boot(struct drm_crtc *crtc); int vc4_crtc_init(struct drm_device *drm, struct vc4_crtc *vc4_crtc, const struct drm_crtc_funcs *crtc_funcs, const struct drm_crtc_helper_funcs *crtc_helper_funcs); -void vc4_crtc_destroy(struct drm_crtc *crtc); int vc4_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, @@ -861,6 +859,8 @@ void vc4_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state); void vc4_crtc_reset(struct drm_crtc *crtc); void vc4_crtc_handle_vblank(struct vc4_crtc *crtc); +void vc4_crtc_send_vblank(struct drm_crtc *crtc); +int vc4_crtc_late_register(struct drm_crtc *crtc); void vc4_crtc_get_margins(struct drm_crtc_state *state, unsigned int *left, unsigned int *right, unsigned int *top, unsigned int *bottom); @@ -868,25 +868,27 @@ void vc4_crtc_get_margins(struct drm_crtc_state *state, /* vc4_debugfs.c */ void vc4_debugfs_init(struct drm_minor *minor); #ifdef CONFIG_DEBUG_FS -void vc4_debugfs_add_file(struct drm_device *drm, - const char *filename, - int (*show)(struct seq_file*, void*), - void *data); -void vc4_debugfs_add_regset32(struct drm_device *drm, - const char *filename, - struct debugfs_regset32 *regset); +int vc4_debugfs_add_file(struct drm_minor *minor, + const char *filename, + int (*show)(struct seq_file*, void*), + void *data); +int vc4_debugfs_add_regset32(struct drm_minor *minor, + const char *filename, + struct debugfs_regset32 *regset); #else -static inline void vc4_debugfs_add_file(struct drm_device *drm, - const char *filename, - int (*show)(struct seq_file*, void*), - void *data) +static inline int vc4_debugfs_add_file(struct drm_minor *minor, + const char *filename, + int (*show)(struct seq_file*, void*), + void *data) { + return 0; } -static inline void vc4_debugfs_add_regset32(struct drm_device *drm, - const char *filename, - struct debugfs_regset32 *regset) +static inline int vc4_debugfs_add_regset32(struct drm_minor *minor, + const char *filename, + struct debugfs_regset32 *regset) { + return 0; } #endif @@ -952,13 +954,15 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state) void vc4_hvs_dump_state(struct vc4_hvs *hvs); void vc4_hvs_unmask_underrun(struct vc4_hvs *hvs, int channel); void vc4_hvs_mask_underrun(struct vc4_hvs *hvs, int channel); +int vc4_hvs_debugfs_init(struct drm_minor *minor); /* vc4_kms.c */ int vc4_kms_load(struct drm_device *dev); /* vc4_plane.c */ struct drm_plane *vc4_plane_init(struct drm_device *dev, - enum drm_plane_type type); + enum drm_plane_type type, + uint32_t possible_crtcs); int vc4_plane_create_additional_planes(struct drm_device *dev); u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist); u32 vc4_plane_dlist_size(const struct drm_plane_state *state); @@ -973,6 +977,7 @@ int vc4_v3d_bin_bo_get(struct vc4_dev *vc4, bool *used); void vc4_v3d_bin_bo_put(struct vc4_dev *vc4); int vc4_v3d_pm_get(struct vc4_dev *vc4); void vc4_v3d_pm_put(struct vc4_dev *vc4); +int vc4_v3d_debugfs_init(struct drm_minor *minor); /* vc4_validate.c */ int @@ -984,19 +989,19 @@ vc4_validate_bin_cl(struct drm_device *dev, int vc4_validate_shader_recs(struct drm_device *dev, struct vc4_exec_info *exec); -struct drm_gem_cma_object *vc4_use_bo(struct vc4_exec_info *exec, +struct drm_gem_dma_object *vc4_use_bo(struct vc4_exec_info *exec, uint32_t hindex); int vc4_get_rcl(struct drm_device *dev, struct vc4_exec_info *exec); bool vc4_check_tex_size(struct vc4_exec_info *exec, - struct drm_gem_cma_object *fbo, + struct drm_gem_dma_object *fbo, uint32_t offset, uint8_t tiling_format, uint32_t width, uint32_t height, uint8_t cpp); /* vc4_validate_shader.c */ struct vc4_validated_shader_info * -vc4_validate_shader(struct drm_gem_cma_object *shader_obj); +vc4_validate_shader(struct drm_gem_dma_object *shader_obj); /* vc4_perfmon.c */ void vc4_perfmon_get(struct vc4_perfmon *perfmon); diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c index b7b2c76770dc..878e05d79e81 100644 --- a/drivers/gpu/drm/vc4/vc4_dsi.c +++ b/drivers/gpu/drm/vc4/vc4_dsi.c @@ -549,10 +549,13 @@ struct vc4_dsi_variant { /* General DSI hardware state. */ struct vc4_dsi { + struct vc4_encoder encoder; + struct mipi_dsi_host dsi_host; + + struct kref kref; + struct platform_device *pdev; - struct mipi_dsi_host dsi_host; - struct drm_encoder *encoder; struct drm_bridge *bridge; struct list_head bridge_chain; @@ -600,6 +603,12 @@ struct vc4_dsi { #define host_to_dsi(host) container_of(host, struct vc4_dsi, dsi_host) +static inline struct vc4_dsi * +to_vc4_dsi(struct drm_encoder *encoder) +{ + return container_of(encoder, struct vc4_dsi, encoder.base); +} + static inline void dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val) { @@ -644,18 +653,6 @@ dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val) DSI_WRITE(dsi->variant->port ? DSI1_##offset : DSI0_##offset, val) #define DSI_PORT_BIT(bit) (dsi->variant->port ? DSI1_##bit : DSI0_##bit) -/* VC4 DSI encoder KMS struct */ -struct vc4_dsi_encoder { - struct vc4_encoder base; - struct vc4_dsi *dsi; -}; - -static inline struct vc4_dsi_encoder * -to_vc4_dsi_encoder(struct drm_encoder *encoder) -{ - return container_of(encoder, struct vc4_dsi_encoder, base.base); -} - static const struct debugfs_reg32 dsi0_regs[] = { VC4_REG32(DSI0_CTRL), VC4_REG32(DSI0_STAT), @@ -795,8 +792,7 @@ dsi_esc_timing(u32 ns) static void vc4_dsi_encoder_disable(struct drm_encoder *encoder) { - struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder); - struct vc4_dsi *dsi = vc4_encoder->dsi; + struct vc4_dsi *dsi = to_vc4_dsi(encoder); struct device *dev = &dsi->pdev->dev; struct drm_bridge *iter; @@ -839,8 +835,7 @@ static bool vc4_dsi_encoder_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder); - struct vc4_dsi *dsi = vc4_encoder->dsi; + struct vc4_dsi *dsi = to_vc4_dsi(encoder); struct clk *phy_parent = clk_get_parent(dsi->pll_phy_clock); unsigned long parent_rate = clk_get_rate(phy_parent); unsigned long pixel_clock_hz = mode->clock * 1000; @@ -875,8 +870,7 @@ static bool vc4_dsi_encoder_mode_fixup(struct drm_encoder *encoder, static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) { struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; - struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder); - struct vc4_dsi *dsi = vc4_encoder->dsi; + struct vc4_dsi *dsi = to_vc4_dsi(encoder); struct device *dev = &dsi->pdev->dev; bool debug_dump_regs = false; struct drm_bridge *iter; @@ -1378,6 +1372,24 @@ static const struct drm_encoder_helper_funcs vc4_dsi_encoder_helper_funcs = { .mode_fixup = vc4_dsi_encoder_mode_fixup, }; +static int vc4_dsi_late_register(struct drm_encoder *encoder) +{ + struct drm_device *drm = encoder->dev; + struct vc4_dsi *dsi = to_vc4_dsi(encoder); + int ret; + + ret = vc4_debugfs_add_regset32(drm->primary, dsi->variant->debugfs_name, + &dsi->regset); + if (ret) + return ret; + + return 0; +} + +static const struct drm_encoder_funcs vc4_dsi_encoder_funcs = { + .late_register = vc4_dsi_late_register, +}; + static const struct vc4_dsi_variant bcm2711_dsi1_variant = { .port = 1, .debugfs_name = "dsi1_regs", @@ -1564,26 +1576,50 @@ static void vc4_dsi_dma_chan_release(void *ptr) dsi->reg_dma_chan = NULL; } +static void vc4_dsi_release(struct kref *kref) +{ + struct vc4_dsi *dsi = + container_of(kref, struct vc4_dsi, kref); + + kfree(dsi); +} + +static void vc4_dsi_get(struct vc4_dsi *dsi) +{ + kref_get(&dsi->kref); +} + +static void vc4_dsi_put(struct vc4_dsi *dsi) +{ + kref_put(&dsi->kref, &vc4_dsi_release); +} + +static void vc4_dsi_release_action(struct drm_device *drm, void *ptr) +{ + struct vc4_dsi *dsi = ptr; + + vc4_dsi_put(dsi); +} + static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); struct drm_device *drm = dev_get_drvdata(master); struct vc4_dsi *dsi = dev_get_drvdata(dev); - struct vc4_dsi_encoder *vc4_dsi_encoder; + struct drm_encoder *encoder = &dsi->encoder.base; int ret; - dsi->variant = of_device_get_match_data(dev); + vc4_dsi_get(dsi); - vc4_dsi_encoder = devm_kzalloc(dev, sizeof(*vc4_dsi_encoder), - GFP_KERNEL); - if (!vc4_dsi_encoder) - return -ENOMEM; + ret = drmm_add_action_or_reset(drm, vc4_dsi_release_action, dsi); + if (ret) + return ret; + + dsi->variant = of_device_get_match_data(dev); INIT_LIST_HEAD(&dsi->bridge_chain); - vc4_dsi_encoder->base.type = dsi->variant->port ? - VC4_ENCODER_TYPE_DSI1 : VC4_ENCODER_TYPE_DSI0; - vc4_dsi_encoder->dsi = dsi; - dsi->encoder = &vc4_dsi_encoder->base.base; + dsi->encoder.type = dsi->variant->port ? + VC4_ENCODER_TYPE_DSI1 : VC4_ENCODER_TYPE_DSI0; dsi->regs = vc4_ioremap_regs(pdev, 0); if (IS_ERR(dsi->regs)) @@ -1687,7 +1723,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) return ret; } - dsi->bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0); + dsi->bridge = drmm_of_get_bridge(drm, dev->of_node, 0, 0); if (IS_ERR(dsi->bridge)) return PTR_ERR(dsi->bridge); @@ -1702,10 +1738,20 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) if (ret) return ret; - drm_simple_encoder_init(drm, dsi->encoder, DRM_MODE_ENCODER_DSI); - drm_encoder_helper_add(dsi->encoder, &vc4_dsi_encoder_helper_funcs); + ret = drmm_encoder_init(drm, encoder, + &vc4_dsi_encoder_funcs, + DRM_MODE_ENCODER_DSI, + NULL); + if (ret) + return ret; + + drm_encoder_helper_add(encoder, &vc4_dsi_encoder_helper_funcs); - ret = drm_bridge_attach(dsi->encoder, dsi->bridge, NULL, 0); + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + + ret = drm_bridge_attach(encoder, dsi->bridge, NULL, 0); if (ret) return ret; /* Disable the atomic helper calls into the bridge. We @@ -1713,11 +1759,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) * from our driver, since we need to sequence them within the * encoder's enable/disable paths. */ - list_splice_init(&dsi->encoder->bridge_chain, &dsi->bridge_chain); - - vc4_debugfs_add_regset32(drm, dsi->variant->debugfs_name, &dsi->regset); - - pm_runtime_enable(dev); + list_splice_init(&encoder->bridge_chain, &dsi->bridge_chain); return 0; } @@ -1726,15 +1768,13 @@ static void vc4_dsi_unbind(struct device *dev, struct device *master, void *data) { struct vc4_dsi *dsi = dev_get_drvdata(dev); - - pm_runtime_disable(dev); + struct drm_encoder *encoder = &dsi->encoder.base; /* * Restore the bridge_chain so the bridge detach procedure can happen * normally. */ - list_splice_init(&dsi->bridge_chain, &dsi->encoder->bridge_chain); - drm_encoder_cleanup(dsi->encoder); + list_splice_init(&dsi->bridge_chain, &encoder->bridge_chain); } static const struct component_ops vc4_dsi_ops = { @@ -1747,11 +1787,12 @@ static int vc4_dsi_dev_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct vc4_dsi *dsi; - dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); + dsi = kzalloc(sizeof(*dsi), GFP_KERNEL); if (!dsi) return -ENOMEM; dev_set_drvdata(dev, dsi); + kref_init(&dsi->kref); dsi->pdev = pdev; dsi->dsi_host.ops = &vc4_dsi_host_ops; dsi->dsi_host.dev = dev; @@ -1766,6 +1807,8 @@ static int vc4_dsi_dev_remove(struct platform_device *pdev) struct vc4_dsi *dsi = dev_get_drvdata(dev); mipi_dsi_host_unregister(&dsi->dsi_host); + vc4_dsi_put(dsi); + return 0; } diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c index fe10d9c3fff8..628d40ff3aa1 100644 --- a/drivers/gpu/drm/vc4/vc4_gem.c +++ b/drivers/gpu/drm/vc4/vc4_gem.c @@ -126,7 +126,7 @@ vc4_get_hang_state_ioctl(struct drm_device *dev, void *data, goto err_delete_handle; } bo_state[i].handle = handle; - bo_state[i].paddr = vc4_bo->base.paddr; + bo_state[i].paddr = vc4_bo->base.dma_addr; bo_state[i].size = vc4_bo->base.base.size; } @@ -764,7 +764,7 @@ vc4_cl_lookup_bos(struct drm_device *dev, } exec->bo = kvmalloc_array(exec->bo_count, - sizeof(struct drm_gem_cma_object *), + sizeof(struct drm_gem_dma_object *), GFP_KERNEL | __GFP_ZERO); if (!exec->bo) { DRM_ERROR("Failed to allocate validated BO pointers\n"); @@ -797,7 +797,7 @@ vc4_cl_lookup_bos(struct drm_device *dev, } drm_gem_object_get(bo); - exec->bo[i] = (struct drm_gem_cma_object *)bo; + exec->bo[i] = (struct drm_gem_dma_object *)bo; } spin_unlock(&file_priv->table_lock); @@ -917,16 +917,16 @@ vc4_get_bcl(struct drm_device *dev, struct vc4_exec_info *exec) list_add_tail(&to_vc4_bo(&exec->exec_bo->base)->unref_head, &exec->unref_list); - exec->ct0ca = exec->exec_bo->paddr + bin_offset; + exec->ct0ca = exec->exec_bo->dma_addr + bin_offset; exec->bin_u = bin; exec->shader_rec_v = exec->exec_bo->vaddr + shader_rec_offset; - exec->shader_rec_p = exec->exec_bo->paddr + shader_rec_offset; + exec->shader_rec_p = exec->exec_bo->dma_addr + shader_rec_offset; exec->shader_rec_size = args->shader_rec_size; exec->uniforms_v = exec->exec_bo->vaddr + uniforms_offset; - exec->uniforms_p = exec->exec_bo->paddr + uniforms_offset; + exec->uniforms_p = exec->exec_bo->dma_addr + uniforms_offset; exec->uniforms_size = args->uniforms_size; ret = vc4_validate_bin_cl(dev, @@ -1308,6 +1308,7 @@ static void vc4_gem_destroy(struct drm_device *dev, void *unused); int vc4_gem_init(struct drm_device *dev) { struct vc4_dev *vc4 = to_vc4_dev(dev); + int ret; if (WARN_ON_ONCE(vc4->is_vc5)) return -ENODEV; @@ -1325,10 +1326,15 @@ int vc4_gem_init(struct drm_device *dev) INIT_WORK(&vc4->job_done_work, vc4_job_done_work); - mutex_init(&vc4->power_lock); + ret = drmm_mutex_init(dev, &vc4->power_lock); + if (ret) + return ret; INIT_LIST_HEAD(&vc4->purgeable.list); - mutex_init(&vc4->purgeable.lock); + + ret = drmm_mutex_init(dev, &vc4->purgeable.lock); + if (ret) + return ret; return drmm_add_action_or_reset(dev, vc4_gem_destroy, NULL); } diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 592c3b5d03e6..fda450185c36 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -34,6 +34,7 @@ #include <drm/display/drm_hdmi_helper.h> #include <drm/display/drm_scdc_helper.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_probe_helper.h> #include <drm/drm_simple_kms_helper.h> #include <linux/clk.h> @@ -41,7 +42,6 @@ #include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/of_address.h> -#include <linux/of_gpio.h> #include <linux/of_platform.h> #include <linux/pm_runtime.h> #include <linux/rational.h> @@ -146,7 +146,12 @@ static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) { struct drm_info_node *node = (struct drm_info_node *)m->private; struct vc4_hdmi *vc4_hdmi = node->info_ent->data; + struct drm_device *drm = vc4_hdmi->connector.dev; struct drm_printer p = drm_seq_file_printer(m); + int idx; + + if (!drm_dev_enter(drm, &idx)) + return -ENODEV; drm_print_regset32(&p, &vc4_hdmi->hdmi_regset); drm_print_regset32(&p, &vc4_hdmi->hd_regset); @@ -157,12 +162,23 @@ static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) drm_print_regset32(&p, &vc4_hdmi->ram_regset); drm_print_regset32(&p, &vc4_hdmi->rm_regset); + drm_dev_exit(idx); + return 0; } static void vc4_hdmi_reset(struct vc4_hdmi *vc4_hdmi) { + struct drm_device *drm = vc4_hdmi->connector.dev; unsigned long flags; + int idx; + + /* + * We can be called by our bind callback, when the + * connector->dev pointer might not be initialised yet. + */ + if (drm && !drm_dev_enter(drm, &idx)) + return; spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); @@ -179,11 +195,23 @@ static void vc4_hdmi_reset(struct vc4_hdmi *vc4_hdmi) HDMI_WRITE(HDMI_SW_RESET_CONTROL, 0); spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + + if (drm) + drm_dev_exit(idx); } static void vc5_hdmi_reset(struct vc4_hdmi *vc4_hdmi) { + struct drm_device *drm = vc4_hdmi->connector.dev; unsigned long flags; + int idx; + + /* + * We can be called by our bind callback, when the + * connector->dev pointer might not be initialised yet. + */ + if (drm && !drm_dev_enter(drm, &idx)) + return; reset_control_reset(vc4_hdmi->reset); @@ -195,15 +223,31 @@ static void vc5_hdmi_reset(struct vc4_hdmi *vc4_hdmi) HDMI_READ(HDMI_CLOCK_STOP) | VC4_DVP_HT_CLOCK_STOP_PIXEL); spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + + if (drm) + drm_dev_exit(idx); } #ifdef CONFIG_DRM_VC4_HDMI_CEC static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) { - unsigned long cec_rate = clk_get_rate(vc4_hdmi->cec_clock); + struct drm_device *drm = vc4_hdmi->connector.dev; + unsigned long cec_rate; unsigned long flags; u16 clk_cnt; u32 value; + int idx; + + /* + * This function is called by our runtime_resume implementation + * and thus at bind time, when we haven't registered our + * connector yet and thus don't have a pointer to the DRM + * device. + */ + if (drm && !drm_dev_enter(drm, &idx)) + return; + + cec_rate = clk_get_rate(vc4_hdmi->cec_clock); spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); @@ -219,6 +263,9 @@ static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) HDMI_WRITE(HDMI_CEC_CNTRL_1, value); spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + + if (drm) + drm_dev_exit(idx); } #else static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) {} @@ -267,12 +314,6 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) return connector_status_disconnected; } -static void vc4_hdmi_connector_destroy(struct drm_connector *connector) -{ - drm_connector_unregister(connector); - drm_connector_cleanup(connector); -} - static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) { struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector); @@ -380,7 +421,6 @@ vc4_hdmi_connector_duplicate_state(struct drm_connector *connector) static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { .detect = vc4_hdmi_connector_detect, .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = vc4_hdmi_connector_destroy, .reset = vc4_hdmi_connector_reset, .atomic_duplicate_state = vc4_hdmi_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, @@ -398,10 +438,13 @@ static int vc4_hdmi_connector_init(struct drm_device *dev, struct drm_encoder *encoder = &vc4_hdmi->encoder.base; int ret; - drm_connector_init_with_ddc(dev, connector, - &vc4_hdmi_connector_funcs, - DRM_MODE_CONNECTOR_HDMIA, - vc4_hdmi->ddc); + ret = drmm_connector_init(dev, connector, + &vc4_hdmi_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA, + vc4_hdmi->ddc); + if (ret) + return ret; + drm_connector_helper_add(connector, &vc4_hdmi_connector_helper_funcs); /* @@ -444,25 +487,34 @@ static int vc4_hdmi_stop_packet(struct drm_encoder *encoder, bool poll) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_device *drm = vc4_hdmi->connector.dev; u32 packet_id = type - 0x80; unsigned long flags; + int ret = 0; + int idx; + + if (!drm_dev_enter(drm, &idx)) + return -ENODEV; spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, HDMI_READ(HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id)); spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); - if (!poll) - return 0; + if (poll) { + ret = wait_for(!(HDMI_READ(HDMI_RAM_PACKET_STATUS) & + BIT(packet_id)), 100); + } - return wait_for(!(HDMI_READ(HDMI_RAM_PACKET_STATUS) & - BIT(packet_id)), 100); + drm_dev_exit(idx); + return ret; } static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, union hdmi_infoframe *frame) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_device *drm = vc4_hdmi->connector.dev; u32 packet_id = frame->any.type - 0x80; const struct vc4_hdmi_register *ram_packet_start = &vc4_hdmi->variant->registers[HDMI_RAM_PACKET_START]; @@ -475,6 +527,10 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, unsigned long flags; ssize_t len, i; int ret; + int idx; + + if (!drm_dev_enter(drm, &idx)) + return; WARN_ONCE(!(HDMI_READ(HDMI_RAM_PACKET_CONFIG) & VC4_HDMI_RAM_PACKET_ENABLE), @@ -482,12 +538,12 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, len = hdmi_infoframe_pack(frame, buffer, sizeof(buffer)); if (len < 0) - return; + goto out; ret = vc4_hdmi_stop_packet(encoder, frame->any.type, true); if (ret) { DRM_ERROR("Failed to wait for infoframe to go idle: %d\n", ret); - return; + goto out; } spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); @@ -523,6 +579,9 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, BIT(packet_id)), 100); if (ret) DRM_ERROR("Failed to wait for infoframe to start: %d\n", ret); + +out: + drm_dev_exit(idx); } static void vc4_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame, @@ -672,8 +731,10 @@ static bool vc4_hdmi_supports_scrambling(struct drm_encoder *encoder, static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_device *drm = vc4_hdmi->connector.dev; struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; unsigned long flags; + int idx; lockdep_assert_held(&vc4_hdmi->mutex); @@ -685,6 +746,9 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder) vc4_hdmi->output_format)) return; + if (!drm_dev_enter(drm, &idx)) + return; + drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, true); drm_scdc_set_scrambling(vc4_hdmi->ddc, true); @@ -693,6 +757,8 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder) VC5_HDMI_SCRAMBLER_CTL_ENABLE); spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + drm_dev_exit(idx); + vc4_hdmi->scdc_enabled = true; queue_delayed_work(system_wq, &vc4_hdmi->scrambling_work, @@ -702,7 +768,9 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder) static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_device *drm = vc4_hdmi->connector.dev; unsigned long flags; + int idx; lockdep_assert_held(&vc4_hdmi->mutex); @@ -714,6 +782,9 @@ static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder) if (delayed_work_pending(&vc4_hdmi->scrambling_work)) cancel_delayed_work_sync(&vc4_hdmi->scrambling_work); + if (!drm_dev_enter(drm, &idx)) + return; + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) & ~VC5_HDMI_SCRAMBLER_CTL_ENABLE); @@ -721,6 +792,8 @@ static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder) drm_scdc_set_scrambling(vc4_hdmi->ddc, false); drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, false); + + drm_dev_exit(idx); } static void vc4_hdmi_scrambling_wq(struct work_struct *work) @@ -743,12 +816,17 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder, struct drm_atomic_state *state) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_device *drm = vc4_hdmi->connector.dev; unsigned long flags; + int idx; mutex_lock(&vc4_hdmi->mutex); vc4_hdmi->packet_ram_enabled = false; + if (!drm_dev_enter(drm, &idx)) + goto out; + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, 0); @@ -766,6 +844,9 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder, vc4_hdmi_disable_scrambling(encoder); + drm_dev_exit(idx); + +out: mutex_unlock(&vc4_hdmi->mutex); } @@ -773,11 +854,16 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder, struct drm_atomic_state *state) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_device *drm = vc4_hdmi->connector.dev; unsigned long flags; int ret; + int idx; mutex_lock(&vc4_hdmi->mutex); + if (!drm_dev_enter(drm, &idx)) + goto out; + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_VID_CTL, HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_BLANKPIX); @@ -793,6 +879,9 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder, if (ret < 0) DRM_ERROR("Failed to release power domain: %d\n", ret); + drm_dev_exit(idx); + +out: mutex_unlock(&vc4_hdmi->mutex); } @@ -800,8 +889,13 @@ static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, struct drm_connector_state *state, const struct drm_display_mode *mode) { + struct drm_device *drm = vc4_hdmi->connector.dev; unsigned long flags; u32 csc_ctl; + int idx; + + if (!drm_dev_enter(drm, &idx)) + return; spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); @@ -836,6 +930,8 @@ static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, HDMI_WRITE(HDMI_CSC_CTL, csc_ctl); spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + + drm_dev_exit(idx); } /* @@ -920,6 +1016,7 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, struct drm_connector_state *state, const struct drm_display_mode *mode) { + struct drm_device *drm = vc4_hdmi->connector.dev; struct vc4_hdmi_connector_state *vc4_state = conn_state_to_vc4_hdmi_conn_state(state); unsigned long flags; @@ -928,6 +1025,10 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, u32 csc_chan_ctl = 0; u32 csc_ctl = VC5_MT_CP_CSC_CTL_ENABLE | VC4_SET_FIELD(VC4_HD_CSC_CTL_MODE_CUSTOM, VC5_MT_CP_CSC_CTL_MODE); + int idx; + + if (!drm_dev_enter(drm, &idx)) + return; spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); @@ -970,12 +1071,15 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, HDMI_WRITE(HDMI_CSC_CTL, csc_ctl); spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + + drm_dev_exit(idx); } static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, struct drm_connector_state *state, struct drm_display_mode *mode) { + struct drm_device *drm = vc4_hdmi->connector.dev; bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC; bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE; @@ -995,6 +1099,10 @@ static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, VC4_HDMI_VERTB_VBP)); unsigned long flags; u32 reg; + int idx; + + if (!drm_dev_enter(drm, &idx)) + return; spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); @@ -1027,12 +1135,15 @@ static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, HDMI_WRITE(HDMI_MISC_CONTROL, reg); spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + + drm_dev_exit(idx); } static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, struct drm_connector_state *state, struct drm_display_mode *mode) { + struct drm_device *drm = vc4_hdmi->connector.dev; const struct vc4_hdmi_connector_state *vc4_state = conn_state_to_vc4_hdmi_conn_state(state); bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; @@ -1056,6 +1167,10 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, unsigned char gcp; bool gcp_en; u32 reg; + int idx; + + if (!drm_dev_enter(drm, &idx)) + return; spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); @@ -1132,13 +1247,20 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, HDMI_WRITE(HDMI_CLOCK_STOP, 0); spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + + drm_dev_exit(idx); } static void vc4_hdmi_recenter_fifo(struct vc4_hdmi *vc4_hdmi) { + struct drm_device *drm = vc4_hdmi->connector.dev; unsigned long flags; u32 drift; int ret; + int idx; + + if (!drm_dev_enter(drm, &idx)) + return; spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); @@ -1167,12 +1289,15 @@ static void vc4_hdmi_recenter_fifo(struct vc4_hdmi *vc4_hdmi) VC4_HDMI_FIFO_CTL_RECENTER_DONE, 1); WARN_ONCE(ret, "Timeout waiting for " "VC4_HDMI_FIFO_CTL_RECENTER_DONE"); + + drm_dev_exit(idx); } static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, struct drm_atomic_state *state) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_device *drm = vc4_hdmi->connector.dev; struct drm_connector *connector = &vc4_hdmi->connector; struct drm_connector_state *conn_state = drm_atomic_get_new_connector_state(state, connector); @@ -1183,9 +1308,13 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, unsigned long bvb_rate, hsm_rate; unsigned long flags; int ret; + int idx; mutex_lock(&vc4_hdmi->mutex); + if (!drm_dev_enter(drm, &idx)) + goto out; + /* * As stated in RPi's vc4 firmware "HDMI state machine (HSM) clock must * be faster than pixel clock, infinitesimally faster, tested in @@ -1206,13 +1335,13 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, ret = clk_set_min_rate(vc4_hdmi->hsm_clock, hsm_rate); if (ret) { DRM_ERROR("Failed to set HSM clock rate: %d\n", ret); - goto out; + goto err_dev_exit; } ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev); if (ret < 0) { DRM_ERROR("Failed to retain power domain: %d\n", ret); - goto out; + goto err_dev_exit; } ret = clk_set_rate(vc4_hdmi->pixel_clock, tmds_char_rate); @@ -1264,6 +1393,8 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, if (vc4_hdmi->variant->set_timings) vc4_hdmi->variant->set_timings(vc4_hdmi, conn_state, mode); + drm_dev_exit(idx); + mutex_unlock(&vc4_hdmi->mutex); return; @@ -1272,6 +1403,8 @@ err_disable_pixel_clock: clk_disable_unprepare(vc4_hdmi->pixel_clock); err_put_runtime_pm: pm_runtime_put(&vc4_hdmi->pdev->dev); +err_dev_exit: + drm_dev_exit(idx); out: mutex_unlock(&vc4_hdmi->mutex); return; @@ -1281,14 +1414,19 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder, struct drm_atomic_state *state) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_device *drm = vc4_hdmi->connector.dev; struct drm_connector *connector = &vc4_hdmi->connector; struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; struct drm_connector_state *conn_state = drm_atomic_get_new_connector_state(state, connector); unsigned long flags; + int idx; mutex_lock(&vc4_hdmi->mutex); + if (!drm_dev_enter(drm, &idx)) + return; + if (vc4_hdmi->variant->csc_setup) vc4_hdmi->variant->csc_setup(vc4_hdmi, conn_state, mode); @@ -1296,6 +1434,8 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder, HDMI_WRITE(HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N); spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + drm_dev_exit(idx); + mutex_unlock(&vc4_hdmi->mutex); } @@ -1303,15 +1443,20 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, struct drm_atomic_state *state) { struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_device *drm = vc4_hdmi->connector.dev; struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; struct drm_display_info *display = &vc4_hdmi->connector.display_info; bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC; unsigned long flags; int ret; + int idx; mutex_lock(&vc4_hdmi->mutex); + if (!drm_dev_enter(drm, &idx)) + return; + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_VID_CTL, @@ -1370,6 +1515,7 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, vc4_hdmi_recenter_fifo(vc4_hdmi); vc4_hdmi_enable_scrambling(encoder); + drm_dev_exit(idx); mutex_unlock(&vc4_hdmi->mutex); } @@ -1692,6 +1838,26 @@ static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = { .mode_valid = vc4_hdmi_encoder_mode_valid, }; +static int vc4_hdmi_late_register(struct drm_encoder *encoder) +{ + struct drm_device *drm = encoder->dev; + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + const struct vc4_hdmi_variant *variant = vc4_hdmi->variant; + int ret; + + ret = vc4_debugfs_add_file(drm->primary, variant->debugfs_name, + vc4_hdmi_debugfs_regs, + vc4_hdmi); + if (ret) + return ret; + + return 0; +} + +static const struct drm_encoder_funcs vc4_hdmi_encoder_funcs = { + .late_register = vc4_hdmi_late_register, +}; + static u32 vc4_hdmi_channel_map(struct vc4_hdmi *vc4_hdmi, u32 channel_mask) { int i; @@ -1718,13 +1884,20 @@ static u32 vc5_hdmi_channel_map(struct vc4_hdmi *vc4_hdmi, u32 channel_mask) static bool vc5_hdmi_hp_detect(struct vc4_hdmi *vc4_hdmi) { + struct drm_device *drm = vc4_hdmi->connector.dev; unsigned long flags; u32 hotplug; + int idx; + + if (!drm_dev_enter(drm, &idx)) + return false; spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); hotplug = HDMI_READ(HDMI_HOTPLUG); spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + drm_dev_exit(idx); + return !!(hotplug & VC4_HDMI_HOTPLUG_CONNECTED); } @@ -1732,10 +1905,16 @@ static bool vc5_hdmi_hp_detect(struct vc4_hdmi *vc4_hdmi) static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi, unsigned int samplerate) { - u32 hsm_clock = clk_get_rate(vc4_hdmi->audio_clock); + struct drm_device *drm = vc4_hdmi->connector.dev; + u32 hsm_clock; unsigned long flags; unsigned long n, m; + int idx; + if (!drm_dev_enter(drm, &idx)) + return; + + hsm_clock = clk_get_rate(vc4_hdmi->audio_clock); rational_best_approximation(hsm_clock, samplerate, VC4_HD_MAI_SMP_N_MASK >> VC4_HD_MAI_SMP_N_SHIFT, @@ -1748,6 +1927,8 @@ static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi, VC4_SET_FIELD(n, VC4_HD_MAI_SMP_N) | VC4_SET_FIELD(m - 1, VC4_HD_MAI_SMP_M)); spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + + drm_dev_exit(idx); } static void vc4_hdmi_set_n_cts(struct vc4_hdmi *vc4_hdmi, unsigned int samplerate) @@ -1803,13 +1984,21 @@ static bool vc4_hdmi_audio_can_stream(struct vc4_hdmi *vc4_hdmi) static int vc4_hdmi_audio_startup(struct device *dev, void *data) { struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); + struct drm_device *drm = vc4_hdmi->connector.dev; unsigned long flags; + int ret = 0; + int idx; mutex_lock(&vc4_hdmi->mutex); + if (!drm_dev_enter(drm, &idx)) { + ret = -ENODEV; + goto out; + } + if (!vc4_hdmi_audio_can_stream(vc4_hdmi)) { - mutex_unlock(&vc4_hdmi->mutex); - return -ENODEV; + ret = -ENODEV; + goto out_dev_exit; } vc4_hdmi->audio.streaming = true; @@ -1826,9 +2015,12 @@ static int vc4_hdmi_audio_startup(struct device *dev, void *data) if (vc4_hdmi->variant->phy_rng_enable) vc4_hdmi->variant->phy_rng_enable(vc4_hdmi); +out_dev_exit: + drm_dev_exit(idx); +out: mutex_unlock(&vc4_hdmi->mutex); - return 0; + return ret; } static void vc4_hdmi_audio_reset(struct vc4_hdmi *vc4_hdmi) @@ -1857,10 +2049,15 @@ static void vc4_hdmi_audio_reset(struct vc4_hdmi *vc4_hdmi) static void vc4_hdmi_audio_shutdown(struct device *dev, void *data) { struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); + struct drm_device *drm = vc4_hdmi->connector.dev; unsigned long flags; + int idx; mutex_lock(&vc4_hdmi->mutex); + if (!drm_dev_enter(drm, &idx)) + goto out; + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_MAI_CTL, @@ -1876,6 +2073,9 @@ static void vc4_hdmi_audio_shutdown(struct device *dev, void *data) vc4_hdmi->audio.streaming = false; vc4_hdmi_audio_reset(vc4_hdmi); + drm_dev_exit(idx); + +out: mutex_unlock(&vc4_hdmi->mutex); } @@ -1923,6 +2123,7 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data, struct hdmi_codec_params *params) { struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); + struct drm_device *drm = vc4_hdmi->connector.dev; struct drm_encoder *encoder = &vc4_hdmi->encoder.base; unsigned int sample_rate = params->sample_rate; unsigned int channels = params->channels; @@ -1931,15 +2132,22 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data, u32 channel_map; u32 mai_audio_format; u32 mai_sample_rate; + int ret = 0; + int idx; dev_dbg(dev, "%s: %u Hz, %d bit, %d channels\n", __func__, sample_rate, params->sample_width, channels); mutex_lock(&vc4_hdmi->mutex); + if (!drm_dev_enter(drm, &idx)) { + ret = -ENODEV; + goto out; + } + if (!vc4_hdmi_audio_can_stream(vc4_hdmi)) { - mutex_unlock(&vc4_hdmi->mutex); - return -EINVAL; + ret = -EINVAL; + goto out_dev_exit; } vc4_hdmi_audio_set_mai_clock(vc4_hdmi, sample_rate); @@ -1996,9 +2204,12 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data, memcpy(&vc4_hdmi->audio.infoframe, ¶ms->cea, sizeof(params->cea)); vc4_hdmi_set_audio_infoframe(encoder); +out_dev_exit: + drm_dev_exit(idx); +out: mutex_unlock(&vc4_hdmi->mutex); - return 0; + return ret; } static const struct snd_soc_component_driver vc4_hdmi_audio_cpu_dai_comp = { @@ -2061,6 +2272,14 @@ static struct hdmi_codec_pdata vc4_hdmi_codec_pdata = { .i2s = 1, }; +static void vc4_hdmi_audio_codec_release(void *ptr) +{ + struct vc4_hdmi *vc4_hdmi = ptr; + + platform_device_unregister(vc4_hdmi->audio.codec_pdev); + vc4_hdmi->audio.codec_pdev = NULL; +} + static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) { const struct vc4_hdmi_register *mai_data = @@ -2073,6 +2292,26 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) int index, len; int ret; + /* + * ASoC makes it a bit hard to retrieve a pointer to the + * vc4_hdmi structure. Registering the card will overwrite our + * device drvdata with a pointer to the snd_soc_card structure, + * which can then be used to retrieve whatever drvdata we want + * to associate. + * + * However, that doesn't fly in the case where we wouldn't + * register an ASoC card (because of an old DT that is missing + * the dmas properties for example), then the card isn't + * registered and the device drvdata wouldn't be set. + * + * We can deal with both cases by making sure a snd_soc_card + * pointer and a vc4_hdmi structure are pointing to the same + * memory address, so we can treat them indistinctly without any + * issue. + */ + BUILD_BUG_ON(offsetof(struct vc4_hdmi_audio, card) != 0); + BUILD_BUG_ON(offsetof(struct vc4_hdmi, audio) != 0); + if (!of_find_property(dev->of_node, "dmas", &len) || !len) { dev_warn(dev, "'dmas' DT property is missing or empty, no HDMI audio\n"); @@ -2102,6 +2341,30 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) vc4_hdmi->audio.dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; vc4_hdmi->audio.dma_data.maxburst = 2; + /* + * NOTE: Strictly speaking, we should probably use a DRM-managed + * registration there to avoid removing all the audio components + * by the time the driver doesn't have any user anymore. + * + * However, the ASoC core uses a number of devm_kzalloc calls + * when registering, even when using non-device-managed + * functions (such as in snd_soc_register_component()). + * + * If we call snd_soc_unregister_component() in a DRM-managed + * action, the device-managed actions have already been executed + * and thus we would access memory that has been freed. + * + * Using device-managed hooks here probably leaves us open to a + * bunch of issues if userspace still has a handle on the ALSA + * device when the device is removed. However, this is mitigated + * by the use of drm_dev_enter()/drm_dev_exit() in the audio + * path to prevent the access to the device resources if it + * isn't there anymore. + * + * Then, the vc4_hdmi structure is DRM-managed and thus only + * freed whenever the last user has closed the DRM device file. + * It should thus outlive ALSA in most situations. + */ ret = devm_snd_dmaengine_pcm_register(dev, &pcm_conf, 0); if (ret) { dev_err(dev, "Could not register PCM component: %d\n", ret); @@ -2125,6 +2388,10 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) } vc4_hdmi->audio.codec_pdev = codec_pdev; + ret = devm_add_action_or_reset(dev, vc4_hdmi_audio_codec_release, vc4_hdmi); + if (ret) + return ret; + dai_link->cpus = &vc4_hdmi->audio.cpu; dai_link->codecs = &vc4_hdmi->audio.codec; dai_link->platforms = &vc4_hdmi->audio.platform; @@ -2163,12 +2430,6 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi) } -static void vc4_hdmi_audio_exit(struct vc4_hdmi *vc4_hdmi) -{ - platform_device_unregister(vc4_hdmi->audio.codec_pdev); - vc4_hdmi->audio.codec_pdev = NULL; -} - static irqreturn_t vc4_hdmi_hpd_irq_thread(int irq, void *priv) { struct vc4_hdmi *vc4_hdmi = priv; @@ -2191,21 +2452,19 @@ static int vc4_hdmi_hotplug_init(struct vc4_hdmi *vc4_hdmi) unsigned int hpd_con = platform_get_irq_byname(pdev, "hpd-connected"); unsigned int hpd_rm = platform_get_irq_byname(pdev, "hpd-removed"); - ret = request_threaded_irq(hpd_con, - NULL, - vc4_hdmi_hpd_irq_thread, IRQF_ONESHOT, - "vc4 hdmi hpd connected", vc4_hdmi); + ret = devm_request_threaded_irq(&pdev->dev, hpd_con, + NULL, + vc4_hdmi_hpd_irq_thread, IRQF_ONESHOT, + "vc4 hdmi hpd connected", vc4_hdmi); if (ret) return ret; - ret = request_threaded_irq(hpd_rm, - NULL, - vc4_hdmi_hpd_irq_thread, IRQF_ONESHOT, - "vc4 hdmi hpd disconnected", vc4_hdmi); - if (ret) { - free_irq(hpd_con, vc4_hdmi); + ret = devm_request_threaded_irq(&pdev->dev, hpd_rm, + NULL, + vc4_hdmi_hpd_irq_thread, IRQF_ONESHOT, + "vc4 hdmi hpd disconnected", vc4_hdmi); + if (ret) return ret; - } connector->polled = DRM_CONNECTOR_POLL_HPD; } @@ -2213,16 +2472,6 @@ static int vc4_hdmi_hotplug_init(struct vc4_hdmi *vc4_hdmi) return 0; } -static void vc4_hdmi_hotplug_exit(struct vc4_hdmi *vc4_hdmi) -{ - struct platform_device *pdev = vc4_hdmi->pdev; - - if (vc4_hdmi->variant->external_irq_controller) { - free_irq(platform_get_irq_byname(pdev, "hpd-connected"), vc4_hdmi); - free_irq(platform_get_irq_byname(pdev, "hpd-removed"), vc4_hdmi); - } -} - #ifdef CONFIG_DRM_VC4_HDMI_CEC static irqreturn_t vc4_cec_irq_handler_rx_thread(int irq, void *priv) { @@ -2296,6 +2545,17 @@ static irqreturn_t vc4_cec_irq_handler_tx_bare_locked(struct vc4_hdmi *vc4_hdmi) { u32 cntrl1; + /* + * We don't need to protect the register access using + * drm_dev_enter() there because the interrupt handler lifetime + * is tied to the device itself, and not to the DRM device. + * + * So when the device will be gone, one of the first thing we + * will be doing will be to unregister the interrupt handler, + * and then unregister the DRM device. drm_dev_enter() would + * thus always succeed if we are here. + */ + lockdep_assert_held(&vc4_hdmi->hw_lock); cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1); @@ -2324,6 +2584,17 @@ static irqreturn_t vc4_cec_irq_handler_rx_bare_locked(struct vc4_hdmi *vc4_hdmi) lockdep_assert_held(&vc4_hdmi->hw_lock); + /* + * We don't need to protect the register access using + * drm_dev_enter() there because the interrupt handler lifetime + * is tied to the device itself, and not to the DRM device. + * + * So when the device will be gone, one of the first thing we + * will be doing will be to unregister the interrupt handler, + * and then unregister the DRM device. drm_dev_enter() would + * thus always succeed if we are here. + */ + vc4_hdmi->cec_rx_msg.len = 0; cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1); vc4_cec_read_msg(vc4_hdmi, cntrl1); @@ -2355,6 +2626,17 @@ static irqreturn_t vc4_cec_irq_handler(int irq, void *priv) irqreturn_t ret; u32 cntrl5; + /* + * We don't need to protect the register access using + * drm_dev_enter() there because the interrupt handler lifetime + * is tied to the device itself, and not to the DRM device. + * + * So when the device will be gone, one of the first thing we + * will be doing will be to unregister the interrupt handler, + * and then unregister the DRM device. drm_dev_enter() would + * thus always succeed if we are here. + */ + if (!(stat & VC4_HDMI_CPU_CEC)) return IRQ_NONE; @@ -2375,11 +2657,13 @@ static irqreturn_t vc4_cec_irq_handler(int irq, void *priv) static int vc4_hdmi_cec_enable(struct cec_adapter *adap) { struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap); + struct drm_device *drm = vc4_hdmi->connector.dev; /* clock period in microseconds */ const u32 usecs = 1000000 / CEC_CLOCK_FREQ; unsigned long flags; u32 val; int ret; + int idx; /* * NOTE: This function should really take vc4_hdmi->mutex, but doing so @@ -2392,9 +2676,19 @@ static int vc4_hdmi_cec_enable(struct cec_adapter *adap) * keep it in mind if we were to change that assumption. */ + if (!drm_dev_enter(drm, &idx)) + /* + * We can't return an error code, because the CEC + * framework will emit WARN_ON messages at unbind + * otherwise. + */ + return 0; + ret = pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev); - if (ret) + if (ret) { + drm_dev_exit(idx); return ret; + } spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); @@ -2430,13 +2724,25 @@ static int vc4_hdmi_cec_enable(struct cec_adapter *adap) spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + drm_dev_exit(idx); + return 0; } static int vc4_hdmi_cec_disable(struct cec_adapter *adap) { struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap); + struct drm_device *drm = vc4_hdmi->connector.dev; unsigned long flags; + int idx; + + if (!drm_dev_enter(drm, &idx)) + /* + * We can't return an error code, because the CEC + * framework will emit WARN_ON messages at unbind + * otherwise. + */ + return 0; /* * NOTE: This function should really take vc4_hdmi->mutex, but doing so @@ -2461,6 +2767,8 @@ static int vc4_hdmi_cec_disable(struct cec_adapter *adap) pm_runtime_put(&vc4_hdmi->pdev->dev); + drm_dev_exit(idx); + return 0; } @@ -2475,7 +2783,9 @@ static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable) static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) { struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap); + struct drm_device *drm = vc4_hdmi->connector.dev; unsigned long flags; + int idx; /* * NOTE: This function should really take vc4_hdmi->mutex, but doing so @@ -2488,12 +2798,22 @@ static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) * keep it in mind if we were to change that assumption. */ + if (!drm_dev_enter(drm, &idx)) + /* + * We can't return an error code, because the CEC + * framework will emit WARN_ON messages at unbind + * otherwise. + */ + return 0; + spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); HDMI_WRITE(HDMI_CEC_CNTRL_1, (HDMI_READ(HDMI_CEC_CNTRL_1) & ~VC4_HDMI_CEC_ADDR_MASK) | (log_addr & 0xf) << VC4_HDMI_CEC_ADDR_SHIFT); spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + drm_dev_exit(idx); + return 0; } @@ -2505,6 +2825,7 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, unsigned long flags; u32 val; unsigned int i; + int idx; /* * NOTE: This function should really take vc4_hdmi->mutex, but doing so @@ -2517,8 +2838,12 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, * keep it in mind if we were to change that assumption. */ + if (!drm_dev_enter(dev, &idx)) + return -ENODEV; + if (msg->len > 16) { drm_err(dev, "Attempting to transmit too much data (%d)\n", msg->len); + drm_dev_exit(idx); return -ENOMEM; } @@ -2542,6 +2867,8 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); + drm_dev_exit(idx); + return 0; } @@ -2551,6 +2878,14 @@ static const struct cec_adap_ops vc4_hdmi_cec_adap_ops = { .adap_transmit = vc4_hdmi_cec_adap_transmit, }; +static void vc4_hdmi_cec_release(void *ptr) +{ + struct vc4_hdmi *vc4_hdmi = ptr; + + cec_unregister_adapter(vc4_hdmi->cec_adap); + vc4_hdmi->cec_adap = NULL; +} + static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) { struct cec_connector_info conn_info; @@ -2575,73 +2910,82 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) cec_s_conn_info(vc4_hdmi->cec_adap, &conn_info); if (vc4_hdmi->variant->external_irq_controller) { - ret = request_threaded_irq(platform_get_irq_byname(pdev, "cec-rx"), - vc4_cec_irq_handler_rx_bare, - vc4_cec_irq_handler_rx_thread, 0, - "vc4 hdmi cec rx", vc4_hdmi); + ret = devm_request_threaded_irq(dev, platform_get_irq_byname(pdev, "cec-rx"), + vc4_cec_irq_handler_rx_bare, + vc4_cec_irq_handler_rx_thread, 0, + "vc4 hdmi cec rx", vc4_hdmi); if (ret) goto err_delete_cec_adap; - ret = request_threaded_irq(platform_get_irq_byname(pdev, "cec-tx"), - vc4_cec_irq_handler_tx_bare, - vc4_cec_irq_handler_tx_thread, 0, - "vc4 hdmi cec tx", vc4_hdmi); + ret = devm_request_threaded_irq(dev, platform_get_irq_byname(pdev, "cec-tx"), + vc4_cec_irq_handler_tx_bare, + vc4_cec_irq_handler_tx_thread, 0, + "vc4 hdmi cec tx", vc4_hdmi); if (ret) - goto err_remove_cec_rx_handler; + goto err_delete_cec_adap; } else { - ret = request_threaded_irq(platform_get_irq(pdev, 0), - vc4_cec_irq_handler, - vc4_cec_irq_handler_thread, 0, - "vc4 hdmi cec", vc4_hdmi); + ret = devm_request_threaded_irq(dev, platform_get_irq(pdev, 0), + vc4_cec_irq_handler, + vc4_cec_irq_handler_thread, 0, + "vc4 hdmi cec", vc4_hdmi); if (ret) goto err_delete_cec_adap; } ret = cec_register_adapter(vc4_hdmi->cec_adap, &pdev->dev); if (ret < 0) - goto err_remove_handlers; + goto err_delete_cec_adap; - return 0; - -err_remove_handlers: - if (vc4_hdmi->variant->external_irq_controller) - free_irq(platform_get_irq_byname(pdev, "cec-tx"), vc4_hdmi); - else - free_irq(platform_get_irq(pdev, 0), vc4_hdmi); + /* + * NOTE: Strictly speaking, we should probably use a DRM-managed + * registration there to avoid removing the CEC adapter by the + * time the DRM driver doesn't have any user anymore. + * + * However, the CEC framework already cleans up the CEC adapter + * only when the last user has closed its file descriptor, so we + * don't need to handle it in DRM. + * + * By the time the device-managed hook is executed, we will give + * up our reference to the CEC adapter and therefore don't + * really care when it's actually freed. + * + * There's still a problematic sequence: if we unregister our + * CEC adapter, but the userspace keeps a handle on the CEC + * adapter but not the DRM device for some reason. In such a + * case, our vc4_hdmi structure will be freed, but the + * cec_adapter structure will have a dangling pointer to what + * used to be our HDMI controller. If we get a CEC call at that + * moment, we could end up with a use-after-free. Fortunately, + * the CEC framework already handles this too, by calling + * cec_is_registered() in cec_ioctl() and cec_poll(). + */ + ret = devm_add_action_or_reset(dev, vc4_hdmi_cec_release, vc4_hdmi); + if (ret) + return ret; -err_remove_cec_rx_handler: - if (vc4_hdmi->variant->external_irq_controller) - free_irq(platform_get_irq_byname(pdev, "cec-rx"), vc4_hdmi); + return 0; err_delete_cec_adap: cec_delete_adapter(vc4_hdmi->cec_adap); return ret; } - -static void vc4_hdmi_cec_exit(struct vc4_hdmi *vc4_hdmi) -{ - struct platform_device *pdev = vc4_hdmi->pdev; - - if (vc4_hdmi->variant->external_irq_controller) { - free_irq(platform_get_irq_byname(pdev, "cec-rx"), vc4_hdmi); - free_irq(platform_get_irq_byname(pdev, "cec-tx"), vc4_hdmi); - } else { - free_irq(platform_get_irq(pdev, 0), vc4_hdmi); - } - - cec_unregister_adapter(vc4_hdmi->cec_adap); -} #else static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi) { return 0; } - -static void vc4_hdmi_cec_exit(struct vc4_hdmi *vc4_hdmi) {}; #endif -static int vc4_hdmi_build_regset(struct vc4_hdmi *vc4_hdmi, +static void vc4_hdmi_free_regset(struct drm_device *drm, void *ptr) +{ + struct debugfs_reg32 *regs = ptr; + + kfree(regs); +} + +static int vc4_hdmi_build_regset(struct drm_device *drm, + struct vc4_hdmi *vc4_hdmi, struct debugfs_regset32 *regset, enum vc4_hdmi_regs reg) { @@ -2649,6 +2993,7 @@ static int vc4_hdmi_build_regset(struct vc4_hdmi *vc4_hdmi, struct debugfs_reg32 *regs, *new_regs; unsigned int count = 0; unsigned int i; + int ret; regs = kcalloc(variant->num_registers, sizeof(*regs), GFP_KERNEL); @@ -2674,10 +3019,15 @@ static int vc4_hdmi_build_regset(struct vc4_hdmi *vc4_hdmi, regset->regs = new_regs; regset->nregs = count; + ret = drmm_add_action_or_reset(drm, vc4_hdmi_free_regset, new_regs); + if (ret) + return ret; + return 0; } -static int vc4_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi) +static int vc4_hdmi_init_resources(struct drm_device *drm, + struct vc4_hdmi *vc4_hdmi) { struct platform_device *pdev = vc4_hdmi->pdev; struct device *dev = &pdev->dev; @@ -2691,11 +3041,11 @@ static int vc4_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi) if (IS_ERR(vc4_hdmi->hd_regs)) return PTR_ERR(vc4_hdmi->hd_regs); - ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->hd_regset, VC4_HD); + ret = vc4_hdmi_build_regset(drm, vc4_hdmi, &vc4_hdmi->hd_regset, VC4_HD); if (ret) return ret; - ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->hdmi_regset, VC4_HDMI); + ret = vc4_hdmi_build_regset(drm, vc4_hdmi, &vc4_hdmi->hdmi_regset, VC4_HDMI); if (ret) return ret; @@ -2718,7 +3068,8 @@ static int vc4_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi) return 0; } -static int vc5_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi) +static int vc5_hdmi_init_resources(struct drm_device *drm, + struct vc4_hdmi *vc4_hdmi) { struct platform_device *pdev = vc4_hdmi->pdev; struct device *dev = &pdev->dev; @@ -2820,42 +3171,42 @@ static int vc5_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi) return PTR_ERR(vc4_hdmi->reset); } - ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->hdmi_regset, VC4_HDMI); + ret = vc4_hdmi_build_regset(drm, vc4_hdmi, &vc4_hdmi->hdmi_regset, VC4_HDMI); if (ret) return ret; - ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->hd_regset, VC4_HD); + ret = vc4_hdmi_build_regset(drm, vc4_hdmi, &vc4_hdmi->hd_regset, VC4_HD); if (ret) return ret; - ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->cec_regset, VC5_CEC); + ret = vc4_hdmi_build_regset(drm, vc4_hdmi, &vc4_hdmi->cec_regset, VC5_CEC); if (ret) return ret; - ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->csc_regset, VC5_CSC); + ret = vc4_hdmi_build_regset(drm, vc4_hdmi, &vc4_hdmi->csc_regset, VC5_CSC); if (ret) return ret; - ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->dvp_regset, VC5_DVP); + ret = vc4_hdmi_build_regset(drm, vc4_hdmi, &vc4_hdmi->dvp_regset, VC5_DVP); if (ret) return ret; - ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->phy_regset, VC5_PHY); + ret = vc4_hdmi_build_regset(drm, vc4_hdmi, &vc4_hdmi->phy_regset, VC5_PHY); if (ret) return ret; - ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->ram_regset, VC5_RAM); + ret = vc4_hdmi_build_regset(drm, vc4_hdmi, &vc4_hdmi->ram_regset, VC5_RAM); if (ret) return ret; - ret = vc4_hdmi_build_regset(vc4_hdmi, &vc4_hdmi->rm_regset, VC5_RM); + ret = vc4_hdmi_build_regset(drm, vc4_hdmi, &vc4_hdmi->rm_regset, VC5_RM); if (ret) return ret; return 0; } -static int __maybe_unused vc4_hdmi_runtime_suspend(struct device *dev) +static int vc4_hdmi_runtime_suspend(struct device *dev) { struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); @@ -2898,6 +3249,13 @@ static int vc4_hdmi_runtime_resume(struct device *dev) return 0; } +static void vc4_hdmi_put_ddc_device(void *ptr) +{ + struct vc4_hdmi *vc4_hdmi = ptr; + + put_device(&vc4_hdmi->ddc->dev); +} + static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) { const struct vc4_hdmi_variant *variant = of_device_get_match_data(dev); @@ -2908,10 +3266,14 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) struct device_node *ddc_node; int ret; - vc4_hdmi = devm_kzalloc(dev, sizeof(*vc4_hdmi), GFP_KERNEL); + vc4_hdmi = drmm_kzalloc(drm, sizeof(*vc4_hdmi), GFP_KERNEL); if (!vc4_hdmi) return -ENOMEM; - mutex_init(&vc4_hdmi->mutex); + + ret = drmm_mutex_init(drm, &vc4_hdmi->mutex); + if (ret) + return ret; + spin_lock_init(&vc4_hdmi->hw_lock); INIT_DELAYED_WORK(&vc4_hdmi->scrambling_work, vc4_hdmi_scrambling_wq); @@ -2935,7 +3297,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) if (variant->max_pixel_clock > HDMI_14_MAX_TMDS_CLK) vc4_hdmi->scdc_enabled = true; - ret = variant->init_resources(vc4_hdmi); + ret = variant->init_resources(drm, vc4_hdmi); if (ret) return ret; @@ -2952,13 +3314,16 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) return -EPROBE_DEFER; } + ret = devm_add_action_or_reset(dev, vc4_hdmi_put_ddc_device, vc4_hdmi); + if (ret) + return ret; + /* Only use the GPIO HPD pin if present in the DT, otherwise * we'll use the HDMI core's register. */ vc4_hdmi->hpd_gpio = devm_gpiod_get_optional(dev, "hpd", GPIOD_IN); if (IS_ERR(vc4_hdmi->hpd_gpio)) { - ret = PTR_ERR(vc4_hdmi->hpd_gpio); - goto err_put_ddc; + return PTR_ERR(vc4_hdmi->hpd_gpio); } vc4_hdmi->disable_wifi_frequencies = @@ -2972,17 +3337,17 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) vc4_hdmi->disable_4kp60 = true; } + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + /* - * We need to have the device powered up at this point to call - * our reset hook and for the CEC init. + * We need to have the device powered up at this point to call + * our reset hook and for the CEC init. */ - ret = vc4_hdmi_runtime_resume(dev); + ret = pm_runtime_resume_and_get(dev); if (ret) - goto err_put_ddc; - - pm_runtime_get_noresume(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); + return ret; if ((of_device_is_compatible(dev->of_node, "brcm,bcm2711-hdmi0") || of_device_is_compatible(dev->of_node, "brcm,bcm2711-hdmi1")) && @@ -2992,92 +3357,43 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) clk_prepare_enable(vc4_hdmi->pixel_bvb_clock); } - drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); + ret = drmm_encoder_init(drm, encoder, + &vc4_hdmi_encoder_funcs, + DRM_MODE_ENCODER_TMDS, + NULL); + if (ret) + goto err_put_runtime_pm; + drm_encoder_helper_add(encoder, &vc4_hdmi_encoder_helper_funcs); ret = vc4_hdmi_connector_init(drm, vc4_hdmi); if (ret) - goto err_destroy_encoder; + goto err_put_runtime_pm; ret = vc4_hdmi_hotplug_init(vc4_hdmi); if (ret) - goto err_destroy_conn; + goto err_put_runtime_pm; ret = vc4_hdmi_cec_init(vc4_hdmi); if (ret) - goto err_free_hotplug; + goto err_put_runtime_pm; ret = vc4_hdmi_audio_init(vc4_hdmi); if (ret) - goto err_free_cec; - - vc4_debugfs_add_file(drm, variant->debugfs_name, - vc4_hdmi_debugfs_regs, - vc4_hdmi); + goto err_put_runtime_pm; pm_runtime_put_sync(dev); return 0; -err_free_cec: - vc4_hdmi_cec_exit(vc4_hdmi); -err_free_hotplug: - vc4_hdmi_hotplug_exit(vc4_hdmi); -err_destroy_conn: - vc4_hdmi_connector_destroy(&vc4_hdmi->connector); -err_destroy_encoder: - drm_encoder_cleanup(encoder); +err_put_runtime_pm: pm_runtime_put_sync(dev); - pm_runtime_disable(dev); -err_put_ddc: - put_device(&vc4_hdmi->ddc->dev); return ret; } -static void vc4_hdmi_unbind(struct device *dev, struct device *master, - void *data) -{ - struct vc4_hdmi *vc4_hdmi; - - /* - * ASoC makes it a bit hard to retrieve a pointer to the - * vc4_hdmi structure. Registering the card will overwrite our - * device drvdata with a pointer to the snd_soc_card structure, - * which can then be used to retrieve whatever drvdata we want - * to associate. - * - * However, that doesn't fly in the case where we wouldn't - * register an ASoC card (because of an old DT that is missing - * the dmas properties for example), then the card isn't - * registered and the device drvdata wouldn't be set. - * - * We can deal with both cases by making sure a snd_soc_card - * pointer and a vc4_hdmi structure are pointing to the same - * memory address, so we can treat them indistinctly without any - * issue. - */ - BUILD_BUG_ON(offsetof(struct vc4_hdmi_audio, card) != 0); - BUILD_BUG_ON(offsetof(struct vc4_hdmi, audio) != 0); - vc4_hdmi = dev_get_drvdata(dev); - - kfree(vc4_hdmi->hdmi_regset.regs); - kfree(vc4_hdmi->hd_regset.regs); - - vc4_hdmi_audio_exit(vc4_hdmi); - vc4_hdmi_cec_exit(vc4_hdmi); - vc4_hdmi_hotplug_exit(vc4_hdmi); - vc4_hdmi_connector_destroy(&vc4_hdmi->connector); - drm_encoder_cleanup(&vc4_hdmi->encoder.base); - - pm_runtime_disable(dev); - - put_device(&vc4_hdmi->ddc->dev); -} - static const struct component_ops vc4_hdmi_ops = { .bind = vc4_hdmi_bind, - .unbind = vc4_hdmi_unbind, }; static int vc4_hdmi_dev_probe(struct platform_device *pdev) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index c3ed2b07df23..99b0bc1297be 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -58,7 +58,8 @@ struct vc4_hdmi_variant { /* Callback to get the resources (memory region, interrupts, * clocks, etc) for that variant. */ - int (*init_resources)(struct vc4_hdmi *vc4_hdmi); + int (*init_resources)(struct drm_device *drm, + struct vc4_hdmi *vc4_hdmi); /* Callback to reset the HDMI block */ void (*reset)(struct vc4_hdmi *vc4_hdmi); diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index fbaa741dda5f..9e823e0de197 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -25,6 +25,7 @@ #include <linux/platform_device.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_vblank.h> #include "vc4_drv.h" @@ -66,11 +67,15 @@ static const struct debugfs_reg32 hvs_regs[] = { void vc4_hvs_dump_state(struct vc4_hvs *hvs) { + struct drm_device *drm = &hvs->vc4->base; struct drm_printer p = drm_info_printer(&hvs->pdev->dev); - int i; + int idx, i; drm_print_regset32(&p, &hvs->regset); + if (!drm_dev_enter(drm, &idx)) + return; + DRM_INFO("HVS ctx:\n"); for (i = 0; i < 64; i += 4) { DRM_INFO("0x%08x (%s): 0x%08x 0x%08x 0x%08x 0x%08x\n", @@ -80,6 +85,8 @@ void vc4_hvs_dump_state(struct vc4_hvs *hvs) readl((u32 __iomem *)hvs->dlist + i + 2), readl((u32 __iomem *)hvs->dlist + i + 3)); } + + drm_dev_exit(idx); } static int vc4_hvs_debugfs_underrun(struct seq_file *m, void *data) @@ -175,6 +182,11 @@ static int vc4_hvs_upload_linear_kernel(struct vc4_hvs *hvs, int ret, i; u32 __iomem *dst_kernel; + /* + * NOTE: We don't need a call to drm_dev_enter()/drm_dev_exit() + * here since that function is only called from vc4_hvs_bind(). + */ + ret = drm_mm_insert_node(&hvs->dlist_mm, space, VC4_KERNEL_DWORDS); if (ret) { DRM_ERROR("Failed to allocate space for filter kernel: %d\n", @@ -199,10 +211,15 @@ static int vc4_hvs_upload_linear_kernel(struct vc4_hvs *hvs, static void vc4_hvs_lut_load(struct vc4_hvs *hvs, struct vc4_crtc *vc4_crtc) { + struct drm_device *drm = &hvs->vc4->base; struct drm_crtc *crtc = &vc4_crtc->base; struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); + int idx; u32 i; + if (!drm_dev_enter(drm, &idx)) + return; + /* The LUT memory is laid out with each HVS channel in order, * each of which takes 256 writes for R, 256 for G, then 256 * for B. @@ -217,6 +234,8 @@ static void vc4_hvs_lut_load(struct vc4_hvs *hvs, HVS_WRITE(SCALER_GAMDATA, vc4_crtc->lut_g[i]); for (i = 0; i < crtc->gamma_size; i++) HVS_WRITE(SCALER_GAMDATA, vc4_crtc->lut_b[i]); + + drm_dev_exit(idx); } static void vc4_hvs_update_gamma_lut(struct vc4_hvs *hvs, @@ -238,7 +257,12 @@ static void vc4_hvs_update_gamma_lut(struct vc4_hvs *hvs, u8 vc4_hvs_get_fifo_frame_count(struct vc4_hvs *hvs, unsigned int fifo) { + struct drm_device *drm = &hvs->vc4->base; u8 field = 0; + int idx; + + if (!drm_dev_enter(drm, &idx)) + return 0; switch (fifo) { case 0: @@ -255,6 +279,7 @@ u8 vc4_hvs_get_fifo_frame_count(struct vc4_hvs *hvs, unsigned int fifo) break; } + drm_dev_exit(idx); return field; } @@ -267,6 +292,12 @@ int vc4_hvs_get_fifo_from_output(struct vc4_hvs *hvs, unsigned int output) if (!vc4->is_vc5) return output; + /* + * NOTE: We should probably use drm_dev_enter()/drm_dev_exit() + * here, but this function is only used during the DRM device + * initialization, so we should be fine. + */ + switch (output) { case 0: return 0; @@ -315,12 +346,17 @@ static int vc4_hvs_init_channel(struct vc4_hvs *hvs, struct drm_crtc *crtc, struct drm_display_mode *mode, bool oneshot) { struct vc4_dev *vc4 = hvs->vc4; + struct drm_device *drm = &vc4->base; struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); struct vc4_crtc_state *vc4_crtc_state = to_vc4_crtc_state(crtc->state); unsigned int chan = vc4_crtc_state->assigned_channel; bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE; u32 dispbkgndx; u32 dispctrl; + int idx; + + if (!drm_dev_enter(drm, &idx)) + return -ENODEV; HVS_WRITE(SCALER_DISPCTRLX(chan), 0); HVS_WRITE(SCALER_DISPCTRLX(chan), SCALER_DISPCTRLX_RESET); @@ -362,14 +398,22 @@ static int vc4_hvs_init_channel(struct vc4_hvs *hvs, struct drm_crtc *crtc, */ vc4_hvs_lut_load(hvs, vc4_crtc); + drm_dev_exit(idx); + return 0; } void vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int chan) { - if (HVS_READ(SCALER_DISPCTRLX(chan)) & SCALER_DISPCTRLX_ENABLE) + struct drm_device *drm = &hvs->vc4->base; + int idx; + + if (!drm_dev_enter(drm, &idx)) return; + if (HVS_READ(SCALER_DISPCTRLX(chan)) & SCALER_DISPCTRLX_ENABLE) + goto out; + HVS_WRITE(SCALER_DISPCTRLX(chan), HVS_READ(SCALER_DISPCTRLX(chan)) | SCALER_DISPCTRLX_RESET); HVS_WRITE(SCALER_DISPCTRLX(chan), @@ -385,6 +429,9 @@ void vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int chan) WARN_ON_ONCE((HVS_READ(SCALER_DISPSTATX(chan)) & (SCALER_DISPSTATX_FULL | SCALER_DISPSTATX_EMPTY)) != SCALER_DISPSTATX_EMPTY); + +out: + drm_dev_exit(idx); } int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) @@ -426,9 +473,15 @@ static void vc4_hvs_install_dlist(struct drm_crtc *crtc) struct vc4_dev *vc4 = to_vc4_dev(dev); struct vc4_hvs *hvs = vc4->hvs; struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state); + int idx; + + if (!drm_dev_enter(dev, &idx)) + return; HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel), vc4_state->mm.start); + + drm_dev_exit(idx); } static void vc4_hvs_update_dlist(struct drm_crtc *crtc) @@ -513,6 +566,12 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc, bool enable_bg_fill = false; u32 __iomem *dlist_start = vc4->hvs->dlist + vc4_state->mm.start; u32 __iomem *dlist_next = dlist_start; + int idx; + + if (!drm_dev_enter(dev, &idx)) { + vc4_crtc_send_vblank(crtc); + return; + } if (debug_dump_regs) { DRM_INFO("CRTC %d HVS before:\n", drm_crtc_index(crtc)); @@ -583,26 +642,44 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc, DRM_INFO("CRTC %d HVS after:\n", drm_crtc_index(crtc)); vc4_hvs_dump_state(hvs); } + + drm_dev_exit(idx); } void vc4_hvs_mask_underrun(struct vc4_hvs *hvs, int channel) { - u32 dispctrl = HVS_READ(SCALER_DISPCTRL); + struct drm_device *drm = &hvs->vc4->base; + u32 dispctrl; + int idx; + if (!drm_dev_enter(drm, &idx)) + return; + + dispctrl = HVS_READ(SCALER_DISPCTRL); dispctrl &= ~SCALER_DISPCTRL_DSPEISLUR(channel); HVS_WRITE(SCALER_DISPCTRL, dispctrl); + + drm_dev_exit(idx); } void vc4_hvs_unmask_underrun(struct vc4_hvs *hvs, int channel) { - u32 dispctrl = HVS_READ(SCALER_DISPCTRL); + struct drm_device *drm = &hvs->vc4->base; + u32 dispctrl; + int idx; + + if (!drm_dev_enter(drm, &idx)) + return; + dispctrl = HVS_READ(SCALER_DISPCTRL); dispctrl |= SCALER_DISPCTRL_DSPEISLUR(channel); HVS_WRITE(SCALER_DISPSTAT, SCALER_DISPSTAT_EUFLOW(channel)); HVS_WRITE(SCALER_DISPCTRL, dispctrl); + + drm_dev_exit(idx); } static void vc4_hvs_report_underrun(struct drm_device *dev) @@ -623,6 +700,17 @@ static irqreturn_t vc4_hvs_irq_handler(int irq, void *data) u32 control; u32 status; + /* + * NOTE: We don't need to protect the register access using + * drm_dev_enter() there because the interrupt handler lifetime + * is tied to the device itself, and not to the DRM device. + * + * So when the device will be gone, one of the first thing we + * will be doing will be to unregister the interrupt handler, + * and then unregister the DRM device. drm_dev_enter() would + * thus always succeed if we are here. + */ + status = HVS_READ(SCALER_DISPSTAT); control = HVS_READ(SCALER_DISPCTRL); @@ -645,6 +733,39 @@ static irqreturn_t vc4_hvs_irq_handler(int irq, void *data) return irqret; } +int vc4_hvs_debugfs_init(struct drm_minor *minor) +{ + struct drm_device *drm = minor->dev; + struct vc4_dev *vc4 = to_vc4_dev(drm); + struct vc4_hvs *hvs = vc4->hvs; + int ret; + + if (!vc4->hvs) + return -ENODEV; + + if (!vc4->is_vc5) + debugfs_create_bool("hvs_load_tracker", S_IRUGO | S_IWUSR, + minor->debugfs_root, + &vc4->load_tracker_enabled); + + ret = vc4_debugfs_add_file(minor, "hvs_dlists", + vc4_hvs_debugfs_dlist, NULL); + if (ret) + return ret; + + ret = vc4_debugfs_add_file(minor, "hvs_underrun", + vc4_hvs_debugfs_underrun, NULL); + if (ret) + return ret; + + ret = vc4_debugfs_add_regset32(minor, "hvs_regs", + &hvs->regset); + if (ret) + return ret; + + return 0; +} + static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); @@ -655,10 +776,9 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) u32 dispctrl; u32 reg; - hvs = devm_kzalloc(&pdev->dev, sizeof(*hvs), GFP_KERNEL); + hvs = drmm_kzalloc(drm, sizeof(*hvs), GFP_KERNEL); if (!hvs) return -ENOMEM; - hvs->vc4 = vc4; hvs->pdev = pdev; @@ -771,12 +891,6 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) if (ret) return ret; - vc4_debugfs_add_regset32(drm, "hvs_regs", &hvs->regset); - vc4_debugfs_add_file(drm, "hvs_underrun", vc4_hvs_debugfs_underrun, - NULL); - vc4_debugfs_add_file(drm, "hvs_dlists", vc4_hvs_debugfs_dlist, - NULL); - return 0; } @@ -786,11 +900,18 @@ static void vc4_hvs_unbind(struct device *dev, struct device *master, struct drm_device *drm = dev_get_drvdata(master); struct vc4_dev *vc4 = to_vc4_dev(drm); struct vc4_hvs *hvs = vc4->hvs; + struct drm_mm_node *node, *next; if (drm_mm_node_allocated(&vc4->hvs->mitchell_netravali_filter)) drm_mm_remove_node(&vc4->hvs->mitchell_netravali_filter); + drm_mm_for_each_node_safe(node, next, &vc4->hvs->dlist_mm) + drm_mm_remove_node(node); + drm_mm_takedown(&vc4->hvs->dlist_mm); + + drm_mm_for_each_node_safe(node, next, &vc4->hvs->lbm_mm) + drm_mm_remove_node(node); drm_mm_takedown(&vc4->hvs->lbm_mm); clk_disable_unprepare(hvs->core_clk); diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c index 2eacfb6773d2..1e6db0121ccd 100644 --- a/drivers/gpu/drm/vc4/vc4_irq.c +++ b/drivers/gpu/drm/vc4/vc4_irq.c @@ -105,7 +105,7 @@ vc4_overflow_mem_work(struct work_struct *work) } vc4->bin_alloc_overflow = BIT(bin_bo_slot); - V3D_WRITE(V3D_BPOA, bo->base.paddr + bin_bo_slot * vc4->bin_alloc_size); + V3D_WRITE(V3D_BPOA, bo->base.dma_addr + bin_bo_slot * vc4->bin_alloc_size); V3D_WRITE(V3D_BPOS, bo->base.base.size); V3D_WRITE(V3D_INTCTL, V3D_INT_OUTOMEM); V3D_WRITE(V3D_INTENA, V3D_INT_OUTOMEM); @@ -295,7 +295,7 @@ vc4_irq_disable(struct drm_device *dev) V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS); /* Finish any interrupt handler still in flight. */ - disable_irq(vc4->irq); + synchronize_irq(vc4->irq); cancel_work_sync(&vc4->overflow_mem_work); } diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index b45dcdfd7306..4419e810103d 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -18,7 +18,6 @@ #include <drm/drm_crtc.h> #include <drm/drm_fourcc.h> #include <drm/drm_gem_framebuffer_helper.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> diff --git a/drivers/gpu/drm/vc4/vc4_perfmon.c b/drivers/gpu/drm/vc4/vc4_perfmon.c index 79a74184d732..c4ac2c946238 100644 --- a/drivers/gpu/drm/vc4/vc4_perfmon.c +++ b/drivers/gpu/drm/vc4/vc4_perfmon.c @@ -133,6 +133,7 @@ void vc4_perfmon_close_file(struct vc4_file *vc4file) idr_for_each(&vc4file->perfmon.idr, vc4_perfmon_idr_del, NULL); idr_destroy(&vc4file->perfmon.idr); mutex_unlock(&vc4file->perfmon.lock); + mutex_destroy(&vc4file->perfmon.lock); } int vc4_perfmon_create_ioctl(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index f27e87a23df7..eff9c63adfa7 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -19,11 +19,10 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_uapi.h> #include <drm/drm_blend.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_gem_atomic_helper.h> -#include <drm/drm_plane_helper.h> #include "uapi/drm/vc4_drm.h" @@ -340,7 +339,7 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) { struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); struct drm_framebuffer *fb = state->fb; - struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); + struct drm_gem_dma_object *bo = drm_fb_dma_get_gem_obj(fb, 0); int num_planes = fb->format->num_planes; struct drm_crtc_state *crtc_state; u32 h_subsample = fb->format->hsub; @@ -360,7 +359,7 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) return ret; for (i = 0; i < num_planes; i++) - vc4_state->offsets[i] = bo->paddr + fb->offsets[i]; + vc4_state->offsets[i] = bo->dma_addr + fb->offsets[i]; /* * We don't support subpixel source positioning for scaling, @@ -1244,14 +1243,14 @@ u32 vc4_plane_dlist_size(const struct drm_plane_state *state) void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb) { struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state); - struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); + struct drm_gem_dma_object *bo = drm_fb_dma_get_gem_obj(fb, 0); uint32_t addr; /* We're skipping the address adjustment for negative origin, * because this is only called on the primary plane. */ WARN_ON_ONCE(plane->state->crtc_x < 0 || plane->state->crtc_y < 0); - addr = bo->paddr + fb->offsets[0]; + addr = bo->dma_addr + fb->offsets[0]; /* Write the new address into the hardware immediately. The * scanout will start from this address as soon as the FIFO @@ -1388,7 +1387,7 @@ static int vc4_prepare_fb(struct drm_plane *plane, if (!state->fb) return 0; - bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base); + bo = to_vc4_bo(&drm_fb_dma_get_gem_obj(state->fb, 0)->base); drm_gem_plane_helper_prepare_fb(plane, state); @@ -1406,7 +1405,7 @@ static void vc4_cleanup_fb(struct drm_plane *plane, if (plane->state->fb == state->fb || !state->fb) return; - bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base); + bo = to_vc4_bo(&drm_fb_dma_get_gem_obj(state->fb, 0)->base); vc4_bo_dec_usecnt(bo); } @@ -1483,8 +1482,6 @@ static bool vc4_format_mod_supported(struct drm_plane *plane, static const struct drm_plane_funcs vc4_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, - .destroy = drm_plane_cleanup, - .set_property = NULL, .reset = vc4_plane_reset, .atomic_duplicate_state = vc4_plane_duplicate_state, .atomic_destroy_state = vc4_plane_destroy_state, @@ -1492,14 +1489,14 @@ static const struct drm_plane_funcs vc4_plane_funcs = { }; struct drm_plane *vc4_plane_init(struct drm_device *dev, - enum drm_plane_type type) + enum drm_plane_type type, + uint32_t possible_crtcs) { struct vc4_dev *vc4 = to_vc4_dev(dev); - struct drm_plane *plane = NULL; + struct drm_plane *plane; struct vc4_plane *vc4_plane; u32 formats[ARRAY_SIZE(hvs_formats)]; int num_formats = 0; - int ret = 0; unsigned i; static const uint64_t modifiers[] = { DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED, @@ -1510,11 +1507,6 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, DRM_FORMAT_MOD_INVALID }; - vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane), - GFP_KERNEL); - if (!vc4_plane) - return ERR_PTR(-ENOMEM); - for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) { if (!hvs_formats[i].hvs5_only || vc4->is_vc5) { formats[num_formats] = hvs_formats[i].drm; @@ -1522,13 +1514,14 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, } } + vc4_plane = drmm_universal_plane_alloc(dev, struct vc4_plane, base, + possible_crtcs, + &vc4_plane_funcs, + formats, num_formats, + modifiers, type, NULL); + if (IS_ERR(vc4_plane)) + return ERR_CAST(vc4_plane); plane = &vc4_plane->base; - ret = drm_universal_plane_init(dev, plane, 0, - &vc4_plane_funcs, - formats, num_formats, - modifiers, type, NULL); - if (ret) - return ERR_PTR(ret); if (vc4->is_vc5) drm_plane_helper_add(plane, &vc5_plane_helper_funcs); @@ -1575,13 +1568,11 @@ int vc4_plane_create_additional_planes(struct drm_device *drm) */ for (i = 0; i < 16; i++) { struct drm_plane *plane = - vc4_plane_init(drm, DRM_PLANE_TYPE_OVERLAY); + vc4_plane_init(drm, DRM_PLANE_TYPE_OVERLAY, + GENMASK(drm->mode_config.num_crtc - 1, 0)); if (IS_ERR(plane)) continue; - - plane->possible_crtcs = - GENMASK(drm->mode_config.num_crtc - 1, 0); } drm_for_each_crtc(crtc, drm) { @@ -1589,9 +1580,9 @@ int vc4_plane_create_additional_planes(struct drm_device *drm) * since we overlay planes on the CRTC in the order they were * initialized. */ - cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR); + cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR, + drm_crtc_mask(crtc)); if (!IS_ERR(cursor_plane)) { - cursor_plane->possible_crtcs = drm_crtc_mask(crtc); crtc->cursor = cursor_plane; } } diff --git a/drivers/gpu/drm/vc4/vc4_render_cl.c b/drivers/gpu/drm/vc4/vc4_render_cl.c index f6b7dc3df08c..1bda5010f15a 100644 --- a/drivers/gpu/drm/vc4/vc4_render_cl.c +++ b/drivers/gpu/drm/vc4/vc4_render_cl.c @@ -40,14 +40,14 @@ #include "vc4_packet.h" struct vc4_rcl_setup { - struct drm_gem_cma_object *color_read; - struct drm_gem_cma_object *color_write; - struct drm_gem_cma_object *zs_read; - struct drm_gem_cma_object *zs_write; - struct drm_gem_cma_object *msaa_color_write; - struct drm_gem_cma_object *msaa_zs_write; - - struct drm_gem_cma_object *rcl; + struct drm_gem_dma_object *color_read; + struct drm_gem_dma_object *color_write; + struct drm_gem_dma_object *zs_read; + struct drm_gem_dma_object *zs_write; + struct drm_gem_dma_object *msaa_color_write; + struct drm_gem_dma_object *msaa_zs_write; + + struct drm_gem_dma_object *rcl; u32 next_offset; u32 next_write_bo_index; @@ -97,11 +97,11 @@ static void vc4_store_before_load(struct vc4_rcl_setup *setup) * coordinates packet, and instead just store to the address given. */ static uint32_t vc4_full_res_offset(struct vc4_exec_info *exec, - struct drm_gem_cma_object *bo, + struct drm_gem_dma_object *bo, struct drm_vc4_submit_rcl_surface *surf, uint8_t x, uint8_t y) { - return bo->paddr + surf->offset + VC4_TILE_BUFFER_SIZE * + return bo->dma_addr + surf->offset + VC4_TILE_BUFFER_SIZE * (DIV_ROUND_UP(exec->args->width, 32) * y + x); } @@ -142,7 +142,7 @@ static void emit_tile(struct vc4_exec_info *exec, } else { rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL); rcl_u16(setup, args->color_read.bits); - rcl_u32(setup, setup->color_read->paddr + + rcl_u32(setup, setup->color_read->dma_addr + args->color_read.offset); } } @@ -164,7 +164,7 @@ static void emit_tile(struct vc4_exec_info *exec, } else { rcl_u8(setup, VC4_PACKET_LOAD_TILE_BUFFER_GENERAL); rcl_u16(setup, args->zs_read.bits); - rcl_u32(setup, setup->zs_read->paddr + + rcl_u32(setup, setup->zs_read->dma_addr + args->zs_read.offset); } } @@ -232,7 +232,7 @@ static void emit_tile(struct vc4_exec_info *exec, (last_tile_write ? 0 : VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR)); rcl_u32(setup, - (setup->zs_write->paddr + args->zs_write.offset) | + (setup->zs_write->dma_addr + args->zs_write.offset) | ((last && last_tile_write) ? VC4_LOADSTORE_TILE_BUFFER_EOF : 0)); } @@ -355,7 +355,7 @@ static int vc4_create_rcl_bo(struct drm_device *dev, struct vc4_exec_info *exec, rcl_u8(setup, VC4_PACKET_TILE_RENDERING_MODE_CONFIG); rcl_u32(setup, - (setup->color_write ? (setup->color_write->paddr + + (setup->color_write ? (setup->color_write->dma_addr + args->color_write.offset) : 0)); rcl_u16(setup, args->width); @@ -374,14 +374,14 @@ static int vc4_create_rcl_bo(struct drm_device *dev, struct vc4_exec_info *exec, } BUG_ON(setup->next_offset != size); - exec->ct1ca = setup->rcl->paddr; - exec->ct1ea = setup->rcl->paddr + setup->next_offset; + exec->ct1ca = setup->rcl->dma_addr; + exec->ct1ea = setup->rcl->dma_addr + setup->next_offset; return 0; } static int vc4_full_res_bounds_check(struct vc4_exec_info *exec, - struct drm_gem_cma_object *obj, + struct drm_gem_dma_object *obj, struct drm_vc4_submit_rcl_surface *surf) { struct drm_vc4_submit_cl *args = exec->args; @@ -407,7 +407,7 @@ static int vc4_full_res_bounds_check(struct vc4_exec_info *exec, } static int vc4_rcl_msaa_surface_setup(struct vc4_exec_info *exec, - struct drm_gem_cma_object **obj, + struct drm_gem_dma_object **obj, struct drm_vc4_submit_rcl_surface *surf) { if (surf->flags != 0 || surf->bits != 0) { @@ -433,7 +433,7 @@ static int vc4_rcl_msaa_surface_setup(struct vc4_exec_info *exec, } static int vc4_rcl_surface_setup(struct vc4_exec_info *exec, - struct drm_gem_cma_object **obj, + struct drm_gem_dma_object **obj, struct drm_vc4_submit_rcl_surface *surf, bool is_write) { @@ -533,7 +533,7 @@ static int vc4_rcl_surface_setup(struct vc4_exec_info *exec, static int vc4_rcl_render_config_surface_setup(struct vc4_exec_info *exec, struct vc4_rcl_setup *setup, - struct drm_gem_cma_object **obj, + struct drm_gem_dma_object **obj, struct drm_vc4_submit_rcl_surface *surf) { uint8_t tiling = VC4_GET_FIELD(surf->bits, diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c index d20b0bc51a18..bd181b5a7b52 100644 --- a/drivers/gpu/drm/vc4/vc4_txp.c +++ b/drivers/gpu/drm/vc4/vc4_txp.c @@ -15,8 +15,9 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_edid.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_panel.h> @@ -155,7 +156,6 @@ struct vc4_txp { struct drm_writeback_connector connector; void __iomem *regs; - struct debugfs_regset32 regset; }; static inline struct vc4_txp *encoder_to_vc4_txp(struct drm_encoder *encoder) @@ -276,13 +276,15 @@ static int vc4_txp_connector_atomic_check(struct drm_connector *conn, static void vc4_txp_connector_atomic_commit(struct drm_connector *conn, struct drm_atomic_state *state) { + struct drm_device *drm = conn->dev; struct drm_connector_state *conn_state = drm_atomic_get_new_connector_state(state, conn); struct vc4_txp *txp = connector_to_vc4_txp(conn); - struct drm_gem_cma_object *gem; + struct drm_gem_dma_object *gem; struct drm_display_mode *mode; struct drm_framebuffer *fb; u32 ctrl; + int idx; int i; if (WARN_ON(!conn_state->writeback_job)) @@ -312,8 +314,11 @@ static void vc4_txp_connector_atomic_commit(struct drm_connector *conn, */ ctrl |= TXP_ALPHA_INVERT; - gem = drm_fb_cma_get_gem_obj(fb, 0); - TXP_WRITE(TXP_DST_PTR, gem->paddr + fb->offsets[0]); + if (!drm_dev_enter(drm, &idx)) + return; + + gem = drm_fb_dma_get_gem_obj(fb, 0); + TXP_WRITE(TXP_DST_PTR, gem->dma_addr + fb->offsets[0]); TXP_WRITE(TXP_DST_PITCH, fb->pitches[0]); TXP_WRITE(TXP_DIM, VC4_SET_FIELD(mode->hdisplay, TXP_WIDTH) | @@ -322,6 +327,8 @@ static void vc4_txp_connector_atomic_commit(struct drm_connector *conn, TXP_WRITE(TXP_DST_CTRL, ctrl); drm_writeback_queue_job(&txp->connector, conn_state); + + drm_dev_exit(idx); } static const struct drm_connector_helper_funcs vc4_txp_connector_helper_funcs = { @@ -337,16 +344,10 @@ vc4_txp_connector_detect(struct drm_connector *connector, bool force) return connector_status_connected; } -static void vc4_txp_connector_destroy(struct drm_connector *connector) -{ - drm_connector_unregister(connector); - drm_connector_cleanup(connector); -} - static const struct drm_connector_funcs vc4_txp_connector_funcs = { .detect = vc4_txp_connector_detect, .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = vc4_txp_connector_destroy, + .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, @@ -354,7 +355,12 @@ static const struct drm_connector_funcs vc4_txp_connector_funcs = { static void vc4_txp_encoder_disable(struct drm_encoder *encoder) { + struct drm_device *drm = encoder->dev; struct vc4_txp *txp = encoder_to_vc4_txp(encoder); + int idx; + + if (!drm_dev_enter(drm, &idx)) + return; if (TXP_READ(TXP_DST_CTRL) & TXP_BUSY) { unsigned long timeout = jiffies + msecs_to_jiffies(1000); @@ -369,6 +375,8 @@ static void vc4_txp_encoder_disable(struct drm_encoder *encoder) } TXP_WRITE(TXP_DST_CTRL, TXP_POWERDOWN); + + drm_dev_exit(idx); } static const struct drm_encoder_helper_funcs vc4_txp_encoder_helper_funcs = { @@ -384,13 +392,13 @@ static void vc4_txp_disable_vblank(struct drm_crtc *crtc) {} static const struct drm_crtc_funcs vc4_txp_crtc_funcs = { .set_config = drm_atomic_helper_set_config, - .destroy = vc4_crtc_destroy, .page_flip = vc4_page_flip, .reset = vc4_crtc_reset, .atomic_duplicate_state = vc4_crtc_duplicate_state, .atomic_destroy_state = vc4_crtc_destroy_state, .enable_vblank = vc4_txp_enable_vblank, .disable_vblank = vc4_txp_disable_vblank, + .late_register = vc4_crtc_late_register, }; static int vc4_txp_atomic_check(struct drm_crtc *crtc, @@ -453,6 +461,16 @@ static irqreturn_t vc4_txp_interrupt(int irq, void *data) struct vc4_txp *txp = data; struct vc4_crtc *vc4_crtc = &txp->base; + /* + * We don't need to protect the register access using + * drm_dev_enter() there because the interrupt handler lifetime + * is tied to the device itself, and not to the DRM device. + * + * So when the device will be gone, one of the first thing we + * will be doing will be to unregister the interrupt handler, + * and then unregister the DRM device. drm_dev_enter() would + * thus always succeed if we are here. + */ TXP_WRITE(TXP_DST_CTRL, TXP_READ(TXP_DST_CTRL) & ~TXP_EI); vc4_crtc_handle_vblank(vc4_crtc); drm_writeback_signal_completion(&txp->connector, 0); @@ -461,6 +479,7 @@ static irqreturn_t vc4_txp_interrupt(int irq, void *data) } static const struct vc4_crtc_data vc4_txp_crtc_data = { + .debugfs_name = "txp_regs", .hvs_available_channels = BIT(2), .hvs_output = 2, }; @@ -469,7 +488,6 @@ static int vc4_txp_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); struct drm_device *drm = dev_get_drvdata(master); - struct vc4_dev *vc4 = to_vc4_dev(drm); struct vc4_crtc *vc4_crtc; struct vc4_txp *txp; struct drm_crtc *crtc; @@ -480,7 +498,7 @@ static int vc4_txp_bind(struct device *dev, struct device *master, void *data) if (irq < 0) return irq; - txp = devm_kzalloc(dev, sizeof(*txp), GFP_KERNEL); + txp = drmm_kzalloc(drm, sizeof(*txp), GFP_KERNEL); if (!txp) return -ENOMEM; vc4_crtc = &txp->base; @@ -495,9 +513,9 @@ static int vc4_txp_bind(struct device *dev, struct device *master, void *data) txp->regs = vc4_ioremap_regs(pdev, 0); if (IS_ERR(txp->regs)) return PTR_ERR(txp->regs); - txp->regset.base = txp->regs; - txp->regset.regs = txp_regs; - txp->regset.nregs = ARRAY_SIZE(txp_regs); + vc4_crtc->regset.base = txp->regs; + vc4_crtc->regset.regs = txp_regs; + vc4_crtc->regset.nregs = ARRAY_SIZE(txp_regs); drm_connector_helper_add(&txp->connector.base, &vc4_txp_connector_helper_funcs); @@ -523,9 +541,6 @@ static int vc4_txp_bind(struct device *dev, struct device *master, void *data) return ret; dev_set_drvdata(dev, txp); - vc4->txp = txp; - - vc4_debugfs_add_regset32(drm, "txp_regs", &txp->regset); return 0; } @@ -533,13 +548,9 @@ static int vc4_txp_bind(struct device *dev, struct device *master, void *data) static void vc4_txp_unbind(struct device *dev, struct device *master, void *data) { - struct drm_device *drm = dev_get_drvdata(master); - struct vc4_dev *vc4 = to_vc4_dev(drm); struct vc4_txp *txp = dev_get_drvdata(dev); - vc4_txp_connector_destroy(&txp->connector.base); - - vc4->txp = NULL; + drm_connector_cleanup(&txp->connector.base); } static const struct component_ops vc4_txp_ops = { diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c index cc714dcfe1f2..56abb0d6bc39 100644 --- a/drivers/gpu/drm/vc4/vc4_v3d.c +++ b/drivers/gpu/drm/vc4/vc4_v3d.c @@ -231,7 +231,7 @@ try_again: * if it doesn't fit within the buffer that we allocated up front. * However, it turns out that 16MB is "enough for anybody", and * real-world applications run into allocation failures from the - * overall CMA pool before they make scenes complicated enough to run + * overall DMA pool before they make scenes complicated enough to run * out of bin space. */ static int bin_bo_alloc(struct vc4_dev *vc4) @@ -261,15 +261,15 @@ static int bin_bo_alloc(struct vc4_dev *vc4) dev_err(&v3d->pdev->dev, "Failed to allocate memory for tile binning: " - "%d. You may need to enable CMA or give it " + "%d. You may need to enable DMA or give it " "more memory.", ret); break; } /* Check if this BO won't trigger the addressing bug. */ - if ((bo->base.paddr & 0xf0000000) == - ((bo->base.paddr + bo->base.base.size - 1) & 0xf0000000)) { + if ((bo->base.dma_addr & 0xf0000000) == + ((bo->base.dma_addr + bo->base.base.size - 1) & 0xf0000000)) { vc4->bin_bo = bo; /* Set up for allocating 512KB chunks of @@ -393,14 +393,34 @@ static int vc4_v3d_runtime_resume(struct device *dev) vc4_v3d_init_hw(&vc4->base); - /* We disabled the IRQ as part of vc4_irq_uninstall in suspend. */ - enable_irq(vc4->irq); vc4_irq_enable(&vc4->base); return 0; } #endif +int vc4_v3d_debugfs_init(struct drm_minor *minor) +{ + struct drm_device *drm = minor->dev; + struct vc4_dev *vc4 = to_vc4_dev(drm); + struct vc4_v3d *v3d = vc4->v3d; + int ret; + + if (!vc4->v3d) + return -ENODEV; + + ret = vc4_debugfs_add_file(minor, "v3d_ident", + vc4_v3d_debugfs_ident, NULL); + if (ret) + return ret; + + ret = vc4_debugfs_add_regset32(minor, "v3d_regs", &v3d->regset); + if (ret) + return ret; + + return 0; +} + static int vc4_v3d_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); @@ -443,44 +463,47 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data) } } + ret = platform_get_irq(pdev, 0); + if (ret < 0) + return ret; + vc4->irq = ret; + + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + if (V3D_READ(V3D_IDENT0) != V3D_EXPECTED_IDENT0) { DRM_ERROR("V3D_IDENT0 read 0x%08x instead of 0x%08x\n", V3D_READ(V3D_IDENT0), V3D_EXPECTED_IDENT0); - return -EINVAL; + ret = -EINVAL; + goto err_put_runtime_pm; } - ret = clk_prepare_enable(v3d->clk); - if (ret != 0) - return ret; - /* Reset the binner overflow address/size at setup, to be sure * we don't reuse an old one. */ V3D_WRITE(V3D_BPOA, 0); V3D_WRITE(V3D_BPOS, 0); - vc4_v3d_init_hw(drm); - - ret = platform_get_irq(pdev, 0); - if (ret < 0) - return ret; - vc4->irq = ret; - ret = vc4_irq_install(drm, vc4->irq); if (ret) { DRM_ERROR("Failed to install IRQ handler\n"); - return ret; + goto err_put_runtime_pm; } - pm_runtime_set_active(dev); pm_runtime_use_autosuspend(dev); pm_runtime_set_autosuspend_delay(dev, 40); /* a little over 2 frames. */ - pm_runtime_enable(dev); - - vc4_debugfs_add_file(drm, "v3d_ident", vc4_v3d_debugfs_ident, NULL); - vc4_debugfs_add_regset32(drm, "v3d_regs", &v3d->regset); return 0; + +err_put_runtime_pm: + pm_runtime_put(dev); + + return ret; } static void vc4_v3d_unbind(struct device *dev, struct device *master, @@ -489,8 +512,6 @@ static void vc4_v3d_unbind(struct device *dev, struct device *master, struct drm_device *drm = dev_get_drvdata(master); struct vc4_dev *vc4 = to_vc4_dev(drm); - pm_runtime_disable(dev); - vc4_irq_uninstall(drm); /* Disable the binner's overflow memory address, so the next diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c index 2feba55bcef7..520231af4df9 100644 --- a/drivers/gpu/drm/vc4/vc4_validate.c +++ b/drivers/gpu/drm/vc4/vc4_validate.c @@ -102,11 +102,11 @@ size_is_lt(uint32_t width, uint32_t height, int cpp) height <= 4 * utile_height(cpp)); } -struct drm_gem_cma_object * +struct drm_gem_dma_object * vc4_use_bo(struct vc4_exec_info *exec, uint32_t hindex) { struct vc4_dev *vc4 = exec->dev; - struct drm_gem_cma_object *obj; + struct drm_gem_dma_object *obj; struct vc4_bo *bo; if (WARN_ON_ONCE(vc4->is_vc5)) @@ -129,7 +129,7 @@ vc4_use_bo(struct vc4_exec_info *exec, uint32_t hindex) return obj; } -static struct drm_gem_cma_object * +static struct drm_gem_dma_object * vc4_use_handle(struct vc4_exec_info *exec, uint32_t gem_handles_packet_index) { return vc4_use_bo(exec, exec->bo_index[gem_handles_packet_index]); @@ -160,7 +160,7 @@ gl_shader_rec_size(uint32_t pointer_bits) } bool -vc4_check_tex_size(struct vc4_exec_info *exec, struct drm_gem_cma_object *fbo, +vc4_check_tex_size(struct vc4_exec_info *exec, struct drm_gem_dma_object *fbo, uint32_t offset, uint8_t tiling_format, uint32_t width, uint32_t height, uint8_t cpp) { @@ -263,7 +263,7 @@ validate_increment_semaphore(VALIDATE_ARGS) static int validate_indexed_prim_list(VALIDATE_ARGS) { - struct drm_gem_cma_object *ib; + struct drm_gem_dma_object *ib; uint32_t length = *(uint32_t *)(untrusted + 1); uint32_t offset = *(uint32_t *)(untrusted + 5); uint32_t max_index = *(uint32_t *)(untrusted + 9); @@ -294,7 +294,7 @@ validate_indexed_prim_list(VALIDATE_ARGS) return -EINVAL; } - *(uint32_t *)(validated + 5) = ib->paddr + offset; + *(uint32_t *)(validated + 5) = ib->dma_addr + offset; return 0; } @@ -400,7 +400,7 @@ validate_tile_binning_config(VALIDATE_ARGS) * free when the job completes rendering. */ exec->bin_slots |= BIT(bin_slot); - bin_addr = vc4->bin_bo->base.paddr + bin_slot * vc4->bin_alloc_size; + bin_addr = vc4->bin_bo->base.dma_addr + bin_slot * vc4->bin_alloc_size; /* The tile state data array is 48 bytes per tile, and we put it at * the start of a BO containing both it and the tile alloc. @@ -575,7 +575,7 @@ reloc_tex(struct vc4_exec_info *exec, struct vc4_texture_sample_info *sample, uint32_t texture_handle_index, bool is_cs) { - struct drm_gem_cma_object *tex; + struct drm_gem_dma_object *tex; uint32_t p0 = *(uint32_t *)(uniform_data_u + sample->p_offset[0]); uint32_t p1 = *(uint32_t *)(uniform_data_u + sample->p_offset[1]); uint32_t p2 = (sample->p_offset[2] != ~0 ? @@ -608,7 +608,7 @@ reloc_tex(struct vc4_exec_info *exec, "outside of UBO\n"); goto fail; } - *validated_p0 = tex->paddr + p0; + *validated_p0 = tex->dma_addr + p0; return true; } @@ -736,7 +736,7 @@ reloc_tex(struct vc4_exec_info *exec, offset -= level_size; } - *validated_p0 = tex->paddr + p0; + *validated_p0 = tex->dma_addr + p0; if (is_cs) { exec->bin_dep_seqno = max(exec->bin_dep_seqno, @@ -765,7 +765,7 @@ validate_gl_shader_rec(struct drm_device *dev, 28, /* cs */ }; uint32_t shader_reloc_count = ARRAY_SIZE(shader_reloc_offsets); - struct drm_gem_cma_object *bo[ARRAY_SIZE(shader_reloc_offsets) + 8]; + struct drm_gem_dma_object *bo[ARRAY_SIZE(shader_reloc_offsets) + 8]; uint32_t nr_attributes, nr_relocs, packet_size; int i; @@ -840,7 +840,7 @@ validate_gl_shader_rec(struct drm_device *dev, void *uniform_data_u; uint32_t tex, uni; - *(uint32_t *)(pkt_v + o) = bo[i]->paddr + src_offset; + *(uint32_t *)(pkt_v + o) = bo[i]->dma_addr + src_offset; if (src_offset != 0) { DRM_DEBUG("Shaders must be at offset 0 of " @@ -896,7 +896,7 @@ validate_gl_shader_rec(struct drm_device *dev, } for (i = 0; i < nr_attributes; i++) { - struct drm_gem_cma_object *vbo = + struct drm_gem_dma_object *vbo = bo[ARRAY_SIZE(shader_reloc_offsets) + i]; uint32_t o = 36 + i * 8; uint32_t offset = *(uint32_t *)(pkt_u + o + 0); @@ -928,7 +928,7 @@ validate_gl_shader_rec(struct drm_device *dev, } } - *(uint32_t *)(pkt_v + o) = vbo->paddr + offset; + *(uint32_t *)(pkt_v + o) = vbo->dma_addr + offset; } return 0; diff --git a/drivers/gpu/drm/vc4/vc4_validate_shaders.c b/drivers/gpu/drm/vc4/vc4_validate_shaders.c index e315aeb5fef5..9745f8810eca 100644 --- a/drivers/gpu/drm/vc4/vc4_validate_shaders.c +++ b/drivers/gpu/drm/vc4/vc4_validate_shaders.c @@ -776,7 +776,7 @@ vc4_handle_branch_target(struct vc4_shader_validation_state *validation_state) } struct vc4_validated_shader_info * -vc4_validate_shader(struct drm_gem_cma_object *shader_obj) +vc4_validate_shader(struct drm_gem_dma_object *shader_obj) { struct vc4_dev *vc4 = to_vc4_dev(shader_obj->base.dev); bool found_shader_end = false; diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c index 11fc3d6f66b1..4a788c1c9058 100644 --- a/drivers/gpu/drm/vc4/vc4_vec.c +++ b/drivers/gpu/drm/vc4/vc4_vec.c @@ -14,6 +14,7 @@ */ #include <drm/drm_atomic_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_edid.h> #include <drm/drm_panel.h> #include <drm/drm_probe_helper.h> @@ -160,12 +161,12 @@ struct vc4_vec_variant { /* General VEC hardware state. */ struct vc4_vec { + struct vc4_encoder encoder; + struct drm_connector connector; + struct platform_device *pdev; const struct vc4_vec_variant *variant; - struct drm_encoder *encoder; - struct drm_connector *connector; - void __iomem *regs; struct clk *clock; @@ -178,30 +179,12 @@ struct vc4_vec { #define VEC_READ(offset) readl(vec->regs + (offset)) #define VEC_WRITE(offset, val) writel(val, vec->regs + (offset)) -/* VC4 VEC encoder KMS struct */ -struct vc4_vec_encoder { - struct vc4_encoder base; - struct vc4_vec *vec; -}; - -static inline struct vc4_vec_encoder * -to_vc4_vec_encoder(struct drm_encoder *encoder) +static inline struct vc4_vec * +encoder_to_vc4_vec(struct drm_encoder *encoder) { - return container_of(encoder, struct vc4_vec_encoder, base.base); + return container_of(encoder, struct vc4_vec, encoder.base); } -/* VC4 VEC connector KMS struct */ -struct vc4_vec_connector { - struct drm_connector base; - struct vc4_vec *vec; - - /* Since the connector is attached to just the one encoder, - * this is the reference to it so we can do the best_encoder() - * hook. - */ - struct drm_encoder *encoder; -}; - enum vc4_vec_tv_mode_id { VC4_VEC_TV_MODE_NTSC, VC4_VEC_TV_MODE_NTSC_J, @@ -243,14 +226,30 @@ static const struct debugfs_reg32 vec_regs[] = { static void vc4_vec_ntsc_mode_set(struct vc4_vec *vec) { + struct drm_device *drm = vec->connector.dev; + int idx; + + if (!drm_dev_enter(drm, &idx)) + return; + VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN); VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS); + + drm_dev_exit(idx); } static void vc4_vec_ntsc_j_mode_set(struct vc4_vec *vec) { + struct drm_device *drm = vec->connector.dev; + int idx; + + if (!drm_dev_enter(drm, &idx)) + return; + VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD); VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS); + + drm_dev_exit(idx); } static const struct drm_display_mode ntsc_mode = { @@ -262,17 +261,33 @@ static const struct drm_display_mode ntsc_mode = { static void vc4_vec_pal_mode_set(struct vc4_vec *vec) { + struct drm_device *drm = vec->connector.dev; + int idx; + + if (!drm_dev_enter(drm, &idx)) + return; + VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD); VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS); + + drm_dev_exit(idx); } static void vc4_vec_pal_m_mode_set(struct vc4_vec *vec) { + struct drm_device *drm = vec->connector.dev; + int idx; + + if (!drm_dev_enter(drm, &idx)) + return; + VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD); VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ); VEC_WRITE(VEC_FREQ3_2, 0x223b); VEC_WRITE(VEC_FREQ1_0, 0x61d1); + + drm_dev_exit(idx); } static const struct drm_display_mode pal_mode = { @@ -307,12 +322,6 @@ vc4_vec_connector_detect(struct drm_connector *connector, bool force) return connector_status_unknown; } -static void vc4_vec_connector_destroy(struct drm_connector *connector) -{ - drm_connector_unregister(connector); - drm_connector_cleanup(connector); -} - static int vc4_vec_connector_get_modes(struct drm_connector *connector) { struct drm_connector_state *state = connector->state; @@ -333,7 +342,6 @@ static int vc4_vec_connector_get_modes(struct drm_connector *connector) static const struct drm_connector_funcs vc4_vec_connector_funcs = { .detect = vc4_vec_connector_detect, .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = vc4_vec_connector_destroy, .reset = drm_atomic_helper_connector_reset, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, @@ -343,25 +351,18 @@ static const struct drm_connector_helper_funcs vc4_vec_connector_helper_funcs = .get_modes = vc4_vec_connector_get_modes, }; -static struct drm_connector *vc4_vec_connector_init(struct drm_device *dev, - struct vc4_vec *vec) +static int vc4_vec_connector_init(struct drm_device *dev, struct vc4_vec *vec) { - struct drm_connector *connector = NULL; - struct vc4_vec_connector *vec_connector; - - vec_connector = devm_kzalloc(dev->dev, sizeof(*vec_connector), - GFP_KERNEL); - if (!vec_connector) - return ERR_PTR(-ENOMEM); + struct drm_connector *connector = &vec->connector; + int ret; - connector = &vec_connector->base; connector->interlace_allowed = true; - vec_connector->encoder = vec->encoder; - vec_connector->vec = vec; + ret = drmm_connector_init(dev, connector, &vc4_vec_connector_funcs, + DRM_MODE_CONNECTOR_Composite, NULL); + if (ret) + return ret; - drm_connector_init(dev, connector, &vc4_vec_connector_funcs, - DRM_MODE_CONNECTOR_Composite); drm_connector_helper_add(connector, &vc4_vec_connector_helper_funcs); drm_object_attach_property(&connector->base, @@ -369,16 +370,19 @@ static struct drm_connector *vc4_vec_connector_init(struct drm_device *dev, VC4_VEC_TV_MODE_NTSC); vec->tv_mode = &vc4_vec_tv_modes[VC4_VEC_TV_MODE_NTSC]; - drm_connector_attach_encoder(connector, vec->encoder); + drm_connector_attach_encoder(connector, &vec->encoder.base); - return connector; + return 0; } static void vc4_vec_encoder_disable(struct drm_encoder *encoder) { - struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder); - struct vc4_vec *vec = vc4_vec_encoder->vec; - int ret; + struct drm_device *drm = encoder->dev; + struct vc4_vec *vec = encoder_to_vc4_vec(encoder); + int idx, ret; + + if (!drm_dev_enter(drm, &idx)) + return; VEC_WRITE(VEC_CFG, 0); VEC_WRITE(VEC_DAC_MISC, @@ -392,20 +396,29 @@ static void vc4_vec_encoder_disable(struct drm_encoder *encoder) ret = pm_runtime_put(&vec->pdev->dev); if (ret < 0) { DRM_ERROR("Failed to release power domain: %d\n", ret); - return; + goto err_dev_exit; } + + drm_dev_exit(idx); + return; + +err_dev_exit: + drm_dev_exit(idx); } static void vc4_vec_encoder_enable(struct drm_encoder *encoder) { - struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder); - struct vc4_vec *vec = vc4_vec_encoder->vec; - int ret; + struct drm_device *drm = encoder->dev; + struct vc4_vec *vec = encoder_to_vc4_vec(encoder); + int idx, ret; + + if (!drm_dev_enter(drm, &idx)) + return; ret = pm_runtime_get_sync(&vec->pdev->dev); if (ret < 0) { DRM_ERROR("Failed to retain power domain: %d\n", ret); - return; + goto err_dev_exit; } /* @@ -418,13 +431,13 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder) ret = clk_set_rate(vec->clock, 108000000); if (ret) { DRM_ERROR("Failed to set clock rate: %d\n", ret); - return; + goto err_put_runtime_pm; } ret = clk_prepare_enable(vec->clock); if (ret) { DRM_ERROR("Failed to turn on core clock: %d\n", ret); - return; + goto err_put_runtime_pm; } /* Reset the different blocks */ @@ -460,6 +473,14 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder) VEC_WRITE(VEC_DAC_MISC, VEC_DAC_MISC_VID_ACT | VEC_DAC_MISC_DAC_RST_N); VEC_WRITE(VEC_CFG, VEC_CFG_VEC_EN); + + drm_dev_exit(idx); + return; + +err_put_runtime_pm: + pm_runtime_put(&vec->pdev->dev); +err_dev_exit: + drm_dev_exit(idx); } @@ -474,8 +495,7 @@ static void vc4_vec_encoder_atomic_mode_set(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { - struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder); - struct vc4_vec *vec = vc4_vec_encoder->vec; + struct vc4_vec *vec = encoder_to_vc4_vec(encoder); vec->tv_mode = &vc4_vec_tv_modes[conn_state->tv.mode]; } @@ -503,6 +523,24 @@ static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = { .atomic_mode_set = vc4_vec_encoder_atomic_mode_set, }; +static int vc4_vec_late_register(struct drm_encoder *encoder) +{ + struct drm_device *drm = encoder->dev; + struct vc4_vec *vec = encoder_to_vc4_vec(encoder); + int ret; + + ret = vc4_debugfs_add_regset32(drm->primary, "vec_regs", + &vec->regset); + if (ret) + return ret; + + return 0; +} + +static const struct drm_encoder_funcs vc4_vec_encoder_funcs = { + .late_register = vc4_vec_late_register, +}; + static const struct vc4_vec_variant bcm2835_vec_variant = { .dac_config = VEC_DAC_CONFIG_DAC_CTRL(0xc) | VEC_DAC_CONFIG_DRIVER_CTRL(0xc) | @@ -532,9 +570,7 @@ static int vc4_vec_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); struct drm_device *drm = dev_get_drvdata(master); - struct vc4_dev *vc4 = to_vc4_dev(drm); struct vc4_vec *vec; - struct vc4_vec_encoder *vc4_vec_encoder; int ret; ret = drm_mode_create_tv_properties(drm, ARRAY_SIZE(tv_mode_names), @@ -542,18 +578,11 @@ static int vc4_vec_bind(struct device *dev, struct device *master, void *data) if (ret) return ret; - vec = devm_kzalloc(dev, sizeof(*vec), GFP_KERNEL); + vec = drmm_kzalloc(drm, sizeof(*vec), GFP_KERNEL); if (!vec) return -ENOMEM; - vc4_vec_encoder = devm_kzalloc(dev, sizeof(*vc4_vec_encoder), - GFP_KERNEL); - if (!vc4_vec_encoder) - return -ENOMEM; - vc4_vec_encoder->base.type = VC4_ENCODER_TYPE_VEC; - vc4_vec_encoder->vec = vec; - vec->encoder = &vc4_vec_encoder->base.base; - + vec->encoder.type = VC4_ENCODER_TYPE_VEC; vec->pdev = pdev; vec->variant = (const struct vc4_vec_variant *) of_device_get_match_data(dev); @@ -572,49 +601,30 @@ static int vc4_vec_bind(struct device *dev, struct device *master, void *data) return ret; } - pm_runtime_enable(dev); - - drm_simple_encoder_init(drm, vec->encoder, DRM_MODE_ENCODER_TVDAC); - drm_encoder_helper_add(vec->encoder, &vc4_vec_encoder_helper_funcs); + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; - vec->connector = vc4_vec_connector_init(drm, vec); - if (IS_ERR(vec->connector)) { - ret = PTR_ERR(vec->connector); - goto err_destroy_encoder; - } + ret = drmm_encoder_init(drm, &vec->encoder.base, + &vc4_vec_encoder_funcs, + DRM_MODE_ENCODER_TVDAC, + NULL); + if (ret) + return ret; - dev_set_drvdata(dev, vec); + drm_encoder_helper_add(&vec->encoder.base, &vc4_vec_encoder_helper_funcs); - vc4->vec = vec; + ret = vc4_vec_connector_init(drm, vec); + if (ret) + return ret; - vc4_debugfs_add_regset32(drm, "vec_regs", &vec->regset); + dev_set_drvdata(dev, vec); return 0; - -err_destroy_encoder: - drm_encoder_cleanup(vec->encoder); - pm_runtime_disable(dev); - - return ret; -} - -static void vc4_vec_unbind(struct device *dev, struct device *master, - void *data) -{ - struct drm_device *drm = dev_get_drvdata(master); - struct vc4_dev *vc4 = to_vc4_dev(drm); - struct vc4_vec *vec = dev_get_drvdata(dev); - - vc4_vec_connector_destroy(vec->connector); - drm_encoder_cleanup(vec->encoder); - pm_runtime_disable(dev); - - vc4->vec = NULL; } static const struct component_ops vc4_vec_ops = { .bind = vc4_vec_bind, - .unbind = vc4_vec_unbind, }; static int vc4_vec_dev_probe(struct platform_device *pdev) diff --git a/drivers/gpu/drm/via/Makefile b/drivers/gpu/drm/via/Makefile index 84db4eee7828..8b978dd51a25 100644 --- a/drivers/gpu/drm/via/Makefile +++ b/drivers/gpu/drm/via/Makefile @@ -3,6 +3,6 @@ # Makefile for the drm device driver. This driver provides support for the # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. -via-y := via_irq.o via_drv.o via_map.o via_mm.o via_dma.o via_verifier.o via_video.o via_dmablit.o +via-y := via_dri1.o obj-$(CONFIG_DRM_VIA) +=via.o diff --git a/drivers/gpu/drm/via/via_3d_reg.h b/drivers/gpu/drm/via/via_3d_reg.h index 462375d543b9..eb848508b12b 100644 --- a/drivers/gpu/drm/via/via_3d_reg.h +++ b/drivers/gpu/drm/via/via_3d_reg.h @@ -1,25 +1,7 @@ +/* SPDX-License-Identifier: MIT */ /* - * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. - * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sub license, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. + * Copyright 1998-2011 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2011 S3 Graphics, Inc. All Rights Reserved. */ #ifndef VIA_3D_REG_H @@ -50,6 +32,7 @@ #define HC_ParaType_Palette 0x0003 #define HC_ParaType_PreCR 0x0010 #define HC_ParaType_Auto 0x00fe +#define INV_ParaType_Dummy 0x00300000 /* Transmission Space */ @@ -173,10 +156,10 @@ #define HC_HSPXOS_SHIFT 12 #define HC_HSPYOS_MASK 0x00000fff -/* Command +/* * Command A */ -#define HC_HCmdHeader_MASK 0xfe000000 /*0xffe00000 */ +#define HC_HCmdHeader_MASK 0xfe000000 /*0xffe00000 */ #define HC_HE3Fire_MASK 0x00100000 #define HC_HPMType_MASK 0x000f0000 #define HC_HEFlag_MASK 0x0000e000 @@ -236,6 +219,8 @@ /* Enable Setting */ #define HC_SubA_HEnable 0x0000 +#define HC_HenForce1P_MASK 0x00800000 /* [Force 1 Pipe] */ +#define HC_HenZDCheck_MASK 0x00400000 /* [Z dirty bit settings] */ #define HC_HenTXEnvMap_MASK 0x00200000 #define HC_HenVertexCNT_MASK 0x00100000 #define HC_HenCPUDAZ_MASK 0x00080000 @@ -684,6 +669,12 @@ /* Texture subtype definitions */ +#define HC_SubType_Samp0 0x00000020 +#define HC_SubType_Samp1 0x00000021 + + +/* Texture subtype definitions + */ #define HC_SubType_Tex0 0x00000000 #define HC_SubType_Tex1 0x00000001 #define HC_SubType_TexGeneral 0x000000fe @@ -762,7 +753,13 @@ #define HC_SubA_HTXnBumpM10 0x0092 #define HC_SubA_HTXnBumpM11 0x0093 #define HC_SubA_HTXnLScale 0x0094 -#define HC_SubA_HTXSMD 0x0000 + +#define HC_SubA_HTXSMD 0x0000 +#define HC_SubA_HTXYUV2RGB1 0x0001 +#define HC_SubA_HTXYUV2RGB2 0x0002 +#define HC_SubA_HTXYUV2RGB3 0x0003 +#define HTXYUV2RGB4BT601 (1<<23) +#define HTXYUV2RGB4BT709 (1<<22) /* HC_SubA_HTXnL012BasH 0x0020 */ #define HC_HTXnL0BasH_MASK 0x000000ff @@ -965,6 +962,7 @@ #define HC_HTXnFM_Lum 0x00100000 #define HC_HTXnFM_Alpha 0x00180000 #define HC_HTXnFM_DX 0x00280000 +#define HC_HTXnFM_YUV 0x00300000 #define HC_HTXnFM_ARGB16 0x00880000 #define HC_HTXnFM_ARGB32 0x00980000 #define HC_HTXnFM_ABGR16 0x00a80000 @@ -995,6 +993,12 @@ #define HC_HTXnFM_DX1 (HC_HTXnFM_DX | 0x00010000) #define HC_HTXnFM_DX23 (HC_HTXnFM_DX | 0x00020000) #define HC_HTXnFM_DX45 (HC_HTXnFM_DX | 0x00030000) +/* YUV package mode */ +#define HC_HTXnFM_YUY2 (HC_HTXnFM_YUV | 0x00000000) +/* YUV planner mode */ +#define HC_HTXnFM_YV12 (HC_HTXnFM_YUV | 0x00040000) +/* YUV planner mode */ +#define HC_HTXnFM_IYUV (HC_HTXnFM_YUV | 0x00040000) #define HC_HTXnFM_RGB555 (HC_HTXnFM_ARGB16 | 0x00000000) #define HC_HTXnFM_RGB565 (HC_HTXnFM_ARGB16 | 0x00010000) #define HC_HTXnFM_ARGB1555 (HC_HTXnFM_ARGB16 | 0x00020000) @@ -1023,6 +1027,13 @@ #define HC_HTXnLoc_Local 0x00000000 #define HC_HTXnLoc_Sys 0x00000002 #define HC_HTXnLoc_AGP 0x00000003 + +/* Video Texture */ +#define HC_HTXnYUV2RGBMode_RGB 0x00000000 +#define HC_HTXnYUV2RGBMode_SDTV 0x00000001 +#define HC_HTXnYUV2RGBMode_HDTV 0x00000002 +#define HC_HTXnYUV2RGBMode_TABLE 0x00000003 + /* HC_SubA_HTXnTRAH 0x007f */ #define HC_HTXnTRAH_MASK 0x00ff0000 @@ -1330,9 +1341,9 @@ */ #define HC_HFthRTXA_MASK 0x000000ff -/****************************************************************************** -** Define the Halcyon Internal register access constants. For simulator only. -******************************************************************************/ +/**************************************************************************** + * Define the Halcyon Internal register access constants. For simulator only. + ***************************************************************************/ #define HC_SIMA_HAGPBstL 0x0000 #define HC_SIMA_HAGPBendL 0x0001 #define HC_SIMA_HAGPCMNT 0x0002 @@ -1477,80 +1488,80 @@ #define HC_SIMA_TX0TX1_OFF 0x0050 /*---- start of texture 1 setting ---- */ -#define HC_SIMA_HTX1L0BasL (HC_SIMA_HTX0L0BasL + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L1BasL (HC_SIMA_HTX0L1BasL + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L2BasL (HC_SIMA_HTX0L2BasL + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L3BasL (HC_SIMA_HTX0L3BasL + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L4BasL (HC_SIMA_HTX0L4BasL + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L5BasL (HC_SIMA_HTX0L5BasL + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L6BasL (HC_SIMA_HTX0L6BasL + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L7BasL (HC_SIMA_HTX0L7BasL + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L8BasL (HC_SIMA_HTX0L8BasL + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L9BasL (HC_SIMA_HTX0L9BasL + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1LaBasL (HC_SIMA_HTX0LaBasL + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1LbBasL (HC_SIMA_HTX0LbBasL + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1LcBasL (HC_SIMA_HTX0LcBasL + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1LdBasL (HC_SIMA_HTX0LdBasL + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1LeBasL (HC_SIMA_HTX0LeBasL + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1LfBasL (HC_SIMA_HTX0LfBasL + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L10BasL (HC_SIMA_HTX0L10BasL + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L11BasL (HC_SIMA_HTX0L11BasL + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L012BasH (HC_SIMA_HTX0L012BasH + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L345BasH (HC_SIMA_HTX0L345BasH + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L678BasH (HC_SIMA_HTX0L678BasH + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L9abBasH (HC_SIMA_HTX0L9abBasH + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1LcdeBasH (HC_SIMA_HTX0LcdeBasH + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1Lf1011BasH (HC_SIMA_HTX0Lf1011BasH + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L0Pit (HC_SIMA_HTX0L0Pit + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L1Pit (HC_SIMA_HTX0L1Pit + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L2Pit (HC_SIMA_HTX0L2Pit + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L3Pit (HC_SIMA_HTX0L3Pit + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L4Pit (HC_SIMA_HTX0L4Pit + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L5Pit (HC_SIMA_HTX0L5Pit + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L6Pit (HC_SIMA_HTX0L6Pit + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L7Pit (HC_SIMA_HTX0L7Pit + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L8Pit (HC_SIMA_HTX0L8Pit + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L9Pit (HC_SIMA_HTX0L9Pit + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1LaPit (HC_SIMA_HTX0LaPit + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1LbPit (HC_SIMA_HTX0LbPit + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1LcPit (HC_SIMA_HTX0LcPit + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1LdPit (HC_SIMA_HTX0LdPit + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1LePit (HC_SIMA_HTX0LePit + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1LfPit (HC_SIMA_HTX0LfPit + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L10Pit (HC_SIMA_HTX0L10Pit + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L11Pit (HC_SIMA_HTX0L11Pit + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L0_5WE (HC_SIMA_HTX0L0_5WE + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L6_bWE (HC_SIMA_HTX0L6_bWE + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1Lc_11WE (HC_SIMA_HTX0Lc_11WE + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L0_5HE (HC_SIMA_HTX0L0_5HE + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L6_bHE (HC_SIMA_HTX0L6_bHE + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L0BasL (HC_SIMA_HTX0L0BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L1BasL (HC_SIMA_HTX0L1BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L2BasL (HC_SIMA_HTX0L2BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L3BasL (HC_SIMA_HTX0L3BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L4BasL (HC_SIMA_HTX0L4BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L5BasL (HC_SIMA_HTX0L5BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L6BasL (HC_SIMA_HTX0L6BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L7BasL (HC_SIMA_HTX0L7BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L8BasL (HC_SIMA_HTX0L8BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L9BasL (HC_SIMA_HTX0L9BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LaBasL (HC_SIMA_HTX0LaBasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LbBasL (HC_SIMA_HTX0LbBasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LcBasL (HC_SIMA_HTX0LcBasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LdBasL (HC_SIMA_HTX0LdBasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LeBasL (HC_SIMA_HTX0LeBasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LfBasL (HC_SIMA_HTX0LfBasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L10BasL (HC_SIMA_HTX0L10BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L11BasL (HC_SIMA_HTX0L11BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L012BasH (HC_SIMA_HTX0L012BasH + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L345BasH (HC_SIMA_HTX0L345BasH + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L678BasH (HC_SIMA_HTX0L678BasH + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L9abBasH (HC_SIMA_HTX0L9abBasH + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LcdeBasH (HC_SIMA_HTX0LcdeBasH + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1Lf1011BasH (HC_SIMA_HTX0Lf1011BasH + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L0Pit (HC_SIMA_HTX0L0Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L1Pit (HC_SIMA_HTX0L1Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L2Pit (HC_SIMA_HTX0L2Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L3Pit (HC_SIMA_HTX0L3Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L4Pit (HC_SIMA_HTX0L4Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L5Pit (HC_SIMA_HTX0L5Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L6Pit (HC_SIMA_HTX0L6Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L7Pit (HC_SIMA_HTX0L7Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L8Pit (HC_SIMA_HTX0L8Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L9Pit (HC_SIMA_HTX0L9Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LaPit (HC_SIMA_HTX0LaPit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LbPit (HC_SIMA_HTX0LbPit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LcPit (HC_SIMA_HTX0LcPit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LdPit (HC_SIMA_HTX0LdPit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LePit (HC_SIMA_HTX0LePit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LfPit (HC_SIMA_HTX0LfPit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L10Pit (HC_SIMA_HTX0L10Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L11Pit (HC_SIMA_HTX0L11Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L0_5WE (HC_SIMA_HTX0L0_5WE + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L6_bWE (HC_SIMA_HTX0L6_bWE + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1Lc_11WE (HC_SIMA_HTX0Lc_11WE + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L0_5HE (HC_SIMA_HTX0L0_5HE + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L6_bHE (HC_SIMA_HTX0L6_bHE + HC_SIMA_TX0TX1_OFF) #define HC_SIMA_HTX1Lc_11HE (HC_SIMA_HTX0Lc_11HE + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1L0OS (HC_SIMA_HTX0L0OS + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1TB (HC_SIMA_HTX0TB + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1MPMD (HC_SIMA_HTX0MPMD + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1CLODu (HC_SIMA_HTX0CLODu + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1FM (HC_SIMA_HTX0FM + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1TRCH (HC_SIMA_HTX0TRCH + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1TRCL (HC_SIMA_HTX0TRCL + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1TBC (HC_SIMA_HTX0TBC + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1TRAH (HC_SIMA_HTX0TRAH + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1LTC (HC_SIMA_HTX0LTC + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1LTA (HC_SIMA_HTX0LTA + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1TBLCsat (HC_SIMA_HTX0TBLCsat + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1TBLCop (HC_SIMA_HTX0TBLCop + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1TBLMPfog (HC_SIMA_HTX0TBLMPfog + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1TBLAsat (HC_SIMA_HTX0TBLAsat + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1TBLRCa (HC_SIMA_HTX0TBLRCa + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1TBLRCb (HC_SIMA_HTX0TBLRCb + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1TBLRCc (HC_SIMA_HTX0TBLRCc + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1TBLRCbias (HC_SIMA_HTX0TBLRCbias + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1TBLRAa (HC_SIMA_HTX0TBLRAa + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1TBLRFog (HC_SIMA_HTX0TBLRFog + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1BumpM00 (HC_SIMA_HTX0BumpM00 + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1BumpM01 (HC_SIMA_HTX0BumpM01 + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1BumpM10 (HC_SIMA_HTX0BumpM10 + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1BumpM11 (HC_SIMA_HTX0BumpM11 + HC_SIMA_TX0TX1_OFF) -#define HC_SIMA_HTX1LScale (HC_SIMA_HTX0LScale + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L0OS (HC_SIMA_HTX0L0OS + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TB (HC_SIMA_HTX0TB + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1MPMD (HC_SIMA_HTX0MPMD + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1CLODu (HC_SIMA_HTX0CLODu + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1FM (HC_SIMA_HTX0FM + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TRCH (HC_SIMA_HTX0TRCH + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TRCL (HC_SIMA_HTX0TRCL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TBC (HC_SIMA_HTX0TBC + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TRAH (HC_SIMA_HTX0TRAH + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LTC (HC_SIMA_HTX0LTC + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LTA (HC_SIMA_HTX0LTA + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TBLCsat (HC_SIMA_HTX0TBLCsat + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TBLCop (HC_SIMA_HTX0TBLCop + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TBLMPfog (HC_SIMA_HTX0TBLMPfog + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TBLAsat (HC_SIMA_HTX0TBLAsat + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TBLRCa (HC_SIMA_HTX0TBLRCa + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TBLRCb (HC_SIMA_HTX0TBLRCb + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TBLRCc (HC_SIMA_HTX0TBLRCc + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TBLRCbias (HC_SIMA_HTX0TBLRCbias + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TBLRAa (HC_SIMA_HTX0TBLRAa + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TBLRFog (HC_SIMA_HTX0TBLRFog + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1BumpM00 (HC_SIMA_HTX0BumpM00 + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1BumpM01 (HC_SIMA_HTX0BumpM01 + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1BumpM10 (HC_SIMA_HTX0BumpM10 + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1BumpM11 (HC_SIMA_HTX0BumpM11 + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LScale (HC_SIMA_HTX0LScale + HC_SIMA_TX0TX1_OFF) /*---- end of texture 1 setting ---- 0xaf */ #define HC_SIMA_HTXSMD 0x00b0 @@ -1580,9 +1591,9 @@ #define HC_SIMA_HRErr 0x0445 #define HC_SIMA_FIFOstatus 0x0446 -/****************************************************************************** -** Define the AGP command header. -******************************************************************************/ +/**************************************************************************** + * Define the AGP command header. + ***************************************************************************/ #define HC_ACMD_MASK 0xfe000000 #define HC_ACMD_SUB_MASK 0x0c000000 #define HC_ACMD_HCmdA 0xee000000 @@ -1605,18 +1616,18 @@ #define HC_ACMD_H4COUNT_MASK 0x01fffe00 #define HC_ACMD_H4COUNT_SHIFT 9 -/******************************************************************************** -** Define Header -********************************************************************************/ -#define HC_HEADER2 0xF210F110 +/***************************************************************************** + * Define Header + ****************************************************************************/ +#define HC_HEADER2 0xF210F110 -/******************************************************************************** -** Define Dummy Value -********************************************************************************/ -#define HC_DUMMY 0xCCCCCCCC -/******************************************************************************** -** Define for DMA use -********************************************************************************/ +/***************************************************************************** + * Define Dummy Value + ****************************************************************************/ +#define HC_DUMMY 0xCCCCCCCC +/***************************************************************************** + * Define for DMA use + ****************************************************************************/ #define HALCYON_HEADER2 0XF210F110 #define HALCYON_FIRECMD 0XEE100000 #define HALCYON_FIREMASK 0XFFF00000 @@ -1643,8 +1654,118 @@ #define HC_HAGPBpID_STOP 0x00000002 #define HC_HAGPBpH_MASK 0x00ffffff + #define VIA_VIDEO_HEADER5 0xFE040000 #define VIA_VIDEO_HEADER6 0xFE050000 #define VIA_VIDEO_HEADER7 0xFE060000 #define VIA_VIDEOMASK 0xFFFF0000 + +/***************************************************************************** + * Define for H5 DMA use + ****************************************************************************/ +#define H5_HC_DUMMY 0xCC000000 + +/* Command Header Type */ +#define INV_DUMMY_MASK 0xFF000000 +#define INV_AGPHeader0 0xFE000000 +#define INV_AGPHeader1 0xFE010000 +#define INV_AGPHeader2 0xFE020000 +#define INV_AGPHeader3 0xFE030000 +#define INV_AGPHeader4 0xFE040000 +#define INV_AGPHeader5 0xFE050000 +#define INV_AGPHeader6 0xFE060000 +#define INV_AGPHeader7 0xFE070000 +#define INV_AGPHeader9 0xFE090000 +#define INV_AGPHeaderA 0xFE0A0000 +#define INV_AGPHeader40 0xFE400000 +#define INV_AGPHeader41 0xFE410000 +#define INV_AGPHeader43 0xFE430000 +#define INV_AGPHeader45 0xFE450000 +#define INV_AGPHeader47 0xFE470000 +#define INV_AGPHeader4A 0xFE4A0000 +#define INV_AGPHeader82 0xFE820000 +#define INV_AGPHeader83 0xFE830000 +#define INV_AGPHeader_MASK 0xFFFF0000 +#define INV_AGPHeader2A 0xFE2A0000 +#define INV_AGPHeader25 0xFE250000 +#define INV_AGPHeader20 0xFE200000 +#define INV_AGPHeader23 0xFE230000 +#define INV_AGPHeaderE2 0xFEE20000 +#define INV_AGPHeaderE3 0xFEE30000 + +/*Transmission IO Space*/ +#define INV_REG_CR_TRANS 0x041C +#define INV_REG_CR_BEGIN 0x0420 +#define INV_REG_CR_END 0x0438 + +#define INV_REG_3D_TRANS 0x043C +#define INV_REG_3D_BEGIN 0x0440 +#define INV_REG_3D_END 0x06FC + +#define INV_ParaType_CmdVdata 0x0000 + +/* H5 Enable Setting + */ +#define INV_HC_SubA_HEnable1 0x00 + +#define INV_HC_HenAT4ALLRT_MASK 0x00100000 +#define INV_HC_HenATMRT3_MASK 0x00080000 +#define INV_HC_HenATMRT2_MASK 0x00040000 +#define INV_HC_HenATMRT1_MASK 0x00020000 +#define INV_HC_HenATMRT0_MASK 0x00010000 +#define INV_HC_HenSCMRT3_MASK 0x00008000 +#define INV_HC_HenSCMRT2_MASK 0x00004000 +#define INV_HC_HenSCMRT1_MASK 0x00002000 +#define INV_HC_HenSCMRT0_MASK 0x00001000 +#define INV_HC_HenFOGMRT3_MASK 0x00000800 +#define INV_HC_HenFOGMRT2_MASK 0x00000400 +#define INV_HC_HenFOGMRT1_MASK 0x00000200 +#define INV_HC_HenFOGMRT0_MASK 0x00000100 +#define INV_HC_HenABLMRT3_MASK 0x00000080 +#define INV_HC_HenABLMRT2_MASK 0x00000040 +#define INV_HC_HenABLMRT1_MASK 0x00000020 +#define INV_HC_HenABLMRT0_MASK 0x00000010 +#define INV_HC_HenDTMRT3_MASK 0x00000008 +#define INV_HC_HenDTMRT2_MASK 0x00000004 +#define INV_HC_HenDTMRT1_MASK 0x00000002 +#define INV_HC_HenDTMRT0_MASK 0x00000001 + +#define INV_HC_SubA_HEnable2 0x01 + +#define INV_HC_HenLUL2DR_MASK 0x00800000 +#define INV_HC_HenLDIAMOND_MASK 0x00400000 +#define INV_HC_HenPSPRITE_MASK 0x00200000 +#define INV_HC_HenC2S_MASK 0x00100000 +#define INV_HC_HenFOGPP_MASK 0x00080000 +#define INV_HC_HenSCPP_MASK 0x00040000 +#define INV_HC_HenCPP_MASK 0x00020000 +#define INV_HC_HenCZ_MASK 0x00002000 +#define INV_HC_HenVC_MASK 0x00001000 +#define INV_HC_HenCL_MASK 0x00000800 +#define INV_HC_HenPS_MASK 0x00000400 +#define INV_HC_HenWCZ_MASK 0x00000200 +#define INV_HC_HenTXCH_MASK 0x00000100 +#define INV_HC_HenBFCULL_MASK 0x00000080 +#define INV_HC_HenCW_MASK 0x00000040 +#define INV_HC_HenAA_MASK 0x00000020 +#define INV_HC_HenST_MASK 0x00000010 +#define INV_HC_HenZT_MASK 0x00000008 +#define INV_HC_HenZW_MASK 0x00000004 +#define INV_HC_HenSP_MASK 0x00000002 +#define INV_HC_HenLP_MASK 0x00000001 + +/* H5 Miscellaneous Settings + */ +#define INV_HC_SubA_HCClipTL 0x0080 +#define INV_HC_SubA_HCClipBL 0x0081 +#define INV_HC_SubA_HSClipTL 0x0082 +#define INV_HC_SubA_HSClipBL 0x0083 +#define INV_HC_SubA_HSolidCL 0x0086 +#define INV_HC_SubA_HSolidCH 0x0087 +#define INV_HC_SubA_HGBClipGL 0x0088 +#define INV_HC_SubA_HGBClipGR 0x0089 + + +#define INV_HC_ParaType_Vetex 0x00040000 + #endif diff --git a/drivers/gpu/drm/via/via_dma.c b/drivers/gpu/drm/via/via_dma.c deleted file mode 100644 index 177b0499abf1..000000000000 --- a/drivers/gpu/drm/via/via_dma.c +++ /dev/null @@ -1,744 +0,0 @@ -/* via_dma.c -- DMA support for the VIA Unichrome/Pro - * - * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. - * All Rights Reserved. - * - * Copyright 2004 Digeo, Inc., Palo Alto, CA, U.S.A. - * All Rights Reserved. - * - * Copyright 2004 The Unichrome project. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sub license, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: - * Tungsten Graphics, - * Erdi Chen, - * Thomas Hellstrom. - */ - -#include <linux/delay.h> -#include <linux/uaccess.h> - -#include <drm/drm.h> -#include <drm/drm_device.h> -#include <drm/drm_file.h> -#include <drm/via_drm.h> - -#include "via_drv.h" -#include "via_3d_reg.h" - -#define CMDBUF_ALIGNMENT_SIZE (0x100) -#define CMDBUF_ALIGNMENT_MASK (0x0ff) - -/* defines for VIA 3D registers */ -#define VIA_REG_STATUS 0x400 -#define VIA_REG_TRANSET 0x43C -#define VIA_REG_TRANSPACE 0x440 - -/* VIA_REG_STATUS(0x400): Engine Status */ -#define VIA_CMD_RGTR_BUSY 0x00000080 /* Command Regulator is busy */ -#define VIA_2D_ENG_BUSY 0x00000001 /* 2D Engine is busy */ -#define VIA_3D_ENG_BUSY 0x00000002 /* 3D Engine is busy */ -#define VIA_VR_QUEUE_BUSY 0x00020000 /* Virtual Queue is busy */ - -#define SetReg2DAGP(nReg, nData) { \ - *((uint32_t *)(vb)) = ((nReg) >> 2) | HALCYON_HEADER1; \ - *((uint32_t *)(vb) + 1) = (nData); \ - vb = ((uint32_t *)vb) + 2; \ - dev_priv->dma_low += 8; \ -} - -#define via_flush_write_combine() mb() - -#define VIA_OUT_RING_QW(w1, w2) do { \ - *vb++ = (w1); \ - *vb++ = (w2); \ - dev_priv->dma_low += 8; \ -} while (0) - -static void via_cmdbuf_start(drm_via_private_t *dev_priv); -static void via_cmdbuf_pause(drm_via_private_t *dev_priv); -static void via_cmdbuf_reset(drm_via_private_t *dev_priv); -static void via_cmdbuf_rewind(drm_via_private_t *dev_priv); -static int via_wait_idle(drm_via_private_t *dev_priv); -static void via_pad_cache(drm_via_private_t *dev_priv, int qwords); - -/* - * Free space in command buffer. - */ - -static uint32_t via_cmdbuf_space(drm_via_private_t *dev_priv) -{ - uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; - uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base; - - return ((hw_addr <= dev_priv->dma_low) ? - (dev_priv->dma_high + hw_addr - dev_priv->dma_low) : - (hw_addr - dev_priv->dma_low)); -} - -/* - * How much does the command regulator lag behind? - */ - -static uint32_t via_cmdbuf_lag(drm_via_private_t *dev_priv) -{ - uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; - uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base; - - return ((hw_addr <= dev_priv->dma_low) ? - (dev_priv->dma_low - hw_addr) : - (dev_priv->dma_wrap + dev_priv->dma_low - hw_addr)); -} - -/* - * Check that the given size fits in the buffer, otherwise wait. - */ - -static inline int -via_cmdbuf_wait(drm_via_private_t *dev_priv, unsigned int size) -{ - uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; - uint32_t cur_addr, hw_addr, next_addr; - volatile uint32_t *hw_addr_ptr; - uint32_t count; - hw_addr_ptr = dev_priv->hw_addr_ptr; - cur_addr = dev_priv->dma_low; - next_addr = cur_addr + size + 512 * 1024; - count = 1000000; - do { - hw_addr = *hw_addr_ptr - agp_base; - if (count-- == 0) { - DRM_ERROR - ("via_cmdbuf_wait timed out hw %x cur_addr %x next_addr %x\n", - hw_addr, cur_addr, next_addr); - return -1; - } - if ((cur_addr < hw_addr) && (next_addr >= hw_addr)) - msleep(1); - } while ((cur_addr < hw_addr) && (next_addr >= hw_addr)); - return 0; -} - -/* - * Checks whether buffer head has reach the end. Rewind the ring buffer - * when necessary. - * - * Returns virtual pointer to ring buffer. - */ - -static inline uint32_t *via_check_dma(drm_via_private_t * dev_priv, - unsigned int size) -{ - if ((dev_priv->dma_low + size + 4 * CMDBUF_ALIGNMENT_SIZE) > - dev_priv->dma_high) { - via_cmdbuf_rewind(dev_priv); - } - if (via_cmdbuf_wait(dev_priv, size) != 0) - return NULL; - - return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low); -} - -int via_dma_cleanup(struct drm_device *dev) -{ - if (dev->dev_private) { - drm_via_private_t *dev_priv = - (drm_via_private_t *) dev->dev_private; - - if (dev_priv->ring.virtual_start) { - via_cmdbuf_reset(dev_priv); - - drm_legacy_ioremapfree(&dev_priv->ring.map, dev); - dev_priv->ring.virtual_start = NULL; - } - - } - - return 0; -} - -static int via_initialize(struct drm_device *dev, - drm_via_private_t *dev_priv, - drm_via_dma_init_t *init) -{ - if (!dev_priv || !dev_priv->mmio) { - DRM_ERROR("via_dma_init called before via_map_init\n"); - return -EFAULT; - } - - if (dev_priv->ring.virtual_start != NULL) { - DRM_ERROR("called again without calling cleanup\n"); - return -EFAULT; - } - - if (!dev->agp || !dev->agp->base) { - DRM_ERROR("called with no agp memory available\n"); - return -EFAULT; - } - - if (dev_priv->chipset == VIA_DX9_0) { - DRM_ERROR("AGP DMA is not supported on this chip\n"); - return -EINVAL; - } - - dev_priv->ring.map.offset = dev->agp->base + init->offset; - dev_priv->ring.map.size = init->size; - dev_priv->ring.map.type = 0; - dev_priv->ring.map.flags = 0; - dev_priv->ring.map.mtrr = 0; - - drm_legacy_ioremap(&dev_priv->ring.map, dev); - - if (dev_priv->ring.map.handle == NULL) { - via_dma_cleanup(dev); - DRM_ERROR("can not ioremap virtual address for" - " ring buffer\n"); - return -ENOMEM; - } - - dev_priv->ring.virtual_start = dev_priv->ring.map.handle; - - dev_priv->dma_ptr = dev_priv->ring.virtual_start; - dev_priv->dma_low = 0; - dev_priv->dma_high = init->size; - dev_priv->dma_wrap = init->size; - dev_priv->dma_offset = init->offset; - dev_priv->last_pause_ptr = NULL; - dev_priv->hw_addr_ptr = - (volatile uint32_t *)((char *)dev_priv->mmio->handle + - init->reg_pause_addr); - - via_cmdbuf_start(dev_priv); - - return 0; -} - -static int via_dma_init(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; - drm_via_dma_init_t *init = data; - int retcode = 0; - - switch (init->func) { - case VIA_INIT_DMA: - if (!capable(CAP_SYS_ADMIN)) - retcode = -EPERM; - else - retcode = via_initialize(dev, dev_priv, init); - break; - case VIA_CLEANUP_DMA: - if (!capable(CAP_SYS_ADMIN)) - retcode = -EPERM; - else - retcode = via_dma_cleanup(dev); - break; - case VIA_DMA_INITIALIZED: - retcode = (dev_priv->ring.virtual_start != NULL) ? - 0 : -EFAULT; - break; - default: - retcode = -EINVAL; - break; - } - - return retcode; -} - -static int via_dispatch_cmdbuffer(struct drm_device *dev, drm_via_cmdbuffer_t *cmd) -{ - drm_via_private_t *dev_priv; - uint32_t *vb; - int ret; - - dev_priv = (drm_via_private_t *) dev->dev_private; - - if (dev_priv->ring.virtual_start == NULL) { - DRM_ERROR("called without initializing AGP ring buffer.\n"); - return -EFAULT; - } - - if (cmd->size > VIA_PCI_BUF_SIZE) - return -ENOMEM; - - if (copy_from_user(dev_priv->pci_buf, cmd->buf, cmd->size)) - return -EFAULT; - - /* - * Running this function on AGP memory is dead slow. Therefore - * we run it on a temporary cacheable system memory buffer and - * copy it to AGP memory when ready. - */ - - if ((ret = - via_verify_command_stream((uint32_t *) dev_priv->pci_buf, - cmd->size, dev, 1))) { - return ret; - } - - vb = via_check_dma(dev_priv, (cmd->size < 0x100) ? 0x102 : cmd->size); - if (vb == NULL) - return -EAGAIN; - - memcpy(vb, dev_priv->pci_buf, cmd->size); - - dev_priv->dma_low += cmd->size; - - /* - * Small submissions somehow stalls the CPU. (AGP cache effects?) - * pad to greater size. - */ - - if (cmd->size < 0x100) - via_pad_cache(dev_priv, (0x100 - cmd->size) >> 3); - via_cmdbuf_pause(dev_priv); - - return 0; -} - -int via_driver_dma_quiescent(struct drm_device *dev) -{ - drm_via_private_t *dev_priv = dev->dev_private; - - if (!via_wait_idle(dev_priv)) - return -EBUSY; - return 0; -} - -static int via_flush_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - - LOCK_TEST_WITH_RETURN(dev, file_priv); - - return via_driver_dma_quiescent(dev); -} - -static int via_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - drm_via_cmdbuffer_t *cmdbuf = data; - int ret; - - LOCK_TEST_WITH_RETURN(dev, file_priv); - - DRM_DEBUG("buf %p size %lu\n", cmdbuf->buf, cmdbuf->size); - - ret = via_dispatch_cmdbuffer(dev, cmdbuf); - return ret; -} - -static int via_dispatch_pci_cmdbuffer(struct drm_device *dev, - drm_via_cmdbuffer_t *cmd) -{ - drm_via_private_t *dev_priv = dev->dev_private; - int ret; - - if (cmd->size > VIA_PCI_BUF_SIZE) - return -ENOMEM; - if (copy_from_user(dev_priv->pci_buf, cmd->buf, cmd->size)) - return -EFAULT; - - if ((ret = - via_verify_command_stream((uint32_t *) dev_priv->pci_buf, - cmd->size, dev, 0))) { - return ret; - } - - ret = - via_parse_command_stream(dev, (const uint32_t *)dev_priv->pci_buf, - cmd->size); - return ret; -} - -static int via_pci_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - drm_via_cmdbuffer_t *cmdbuf = data; - int ret; - - LOCK_TEST_WITH_RETURN(dev, file_priv); - - DRM_DEBUG("buf %p size %lu\n", cmdbuf->buf, cmdbuf->size); - - ret = via_dispatch_pci_cmdbuffer(dev, cmdbuf); - return ret; -} - -static inline uint32_t *via_align_buffer(drm_via_private_t *dev_priv, - uint32_t * vb, int qw_count) -{ - for (; qw_count > 0; --qw_count) - VIA_OUT_RING_QW(HC_DUMMY, HC_DUMMY); - return vb; -} - -/* - * This function is used internally by ring buffer management code. - * - * Returns virtual pointer to ring buffer. - */ -static inline uint32_t *via_get_dma(drm_via_private_t *dev_priv) -{ - return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low); -} - -/* - * Hooks a segment of data into the tail of the ring-buffer by - * modifying the pause address stored in the buffer itself. If - * the regulator has already paused, restart it. - */ -static int via_hook_segment(drm_via_private_t *dev_priv, - uint32_t pause_addr_hi, uint32_t pause_addr_lo, - int no_pci_fire) -{ - int paused, count; - volatile uint32_t *paused_at = dev_priv->last_pause_ptr; - uint32_t reader, ptr; - uint32_t diff; - - paused = 0; - via_flush_write_combine(); - (void) *(volatile uint32_t *)(via_get_dma(dev_priv) - 1); - - *paused_at = pause_addr_lo; - via_flush_write_combine(); - (void) *paused_at; - - reader = *(dev_priv->hw_addr_ptr); - ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) + - dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4; - - dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1; - - /* - * If there is a possibility that the command reader will - * miss the new pause address and pause on the old one, - * In that case we need to program the new start address - * using PCI. - */ - - diff = (uint32_t) (ptr - reader) - dev_priv->dma_diff; - count = 10000000; - while (diff == 0 && count--) { - paused = (via_read(dev_priv, 0x41c) & 0x80000000); - if (paused) - break; - reader = *(dev_priv->hw_addr_ptr); - diff = (uint32_t) (ptr - reader) - dev_priv->dma_diff; - } - - paused = via_read(dev_priv, 0x41c) & 0x80000000; - - if (paused && !no_pci_fire) { - reader = *(dev_priv->hw_addr_ptr); - diff = (uint32_t) (ptr - reader) - dev_priv->dma_diff; - diff &= (dev_priv->dma_high - 1); - if (diff != 0 && diff < (dev_priv->dma_high >> 1)) { - DRM_ERROR("Paused at incorrect address. " - "0x%08x, 0x%08x 0x%08x\n", - ptr, reader, dev_priv->dma_diff); - } else if (diff == 0) { - /* - * There is a concern that these writes may stall the PCI bus - * if the GPU is not idle. However, idling the GPU first - * doesn't make a difference. - */ - - via_write(dev_priv, VIA_REG_TRANSET, (HC_ParaType_PreCR << 16)); - via_write(dev_priv, VIA_REG_TRANSPACE, pause_addr_hi); - via_write(dev_priv, VIA_REG_TRANSPACE, pause_addr_lo); - via_read(dev_priv, VIA_REG_TRANSPACE); - } - } - return paused; -} - -static int via_wait_idle(drm_via_private_t *dev_priv) -{ - int count = 10000000; - - while (!(via_read(dev_priv, VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY) && --count) - ; - - while (count && (via_read(dev_priv, VIA_REG_STATUS) & - (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | - VIA_3D_ENG_BUSY))) - --count; - return count; -} - -static uint32_t *via_align_cmd(drm_via_private_t *dev_priv, uint32_t cmd_type, - uint32_t addr, uint32_t *cmd_addr_hi, - uint32_t *cmd_addr_lo, int skip_wait) -{ - uint32_t agp_base; - uint32_t cmd_addr, addr_lo, addr_hi; - uint32_t *vb; - uint32_t qw_pad_count; - - if (!skip_wait) - via_cmdbuf_wait(dev_priv, 2 * CMDBUF_ALIGNMENT_SIZE); - - vb = via_get_dma(dev_priv); - VIA_OUT_RING_QW(HC_HEADER2 | ((VIA_REG_TRANSET >> 2) << 12) | - (VIA_REG_TRANSPACE >> 2), HC_ParaType_PreCR << 16); - agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; - qw_pad_count = (CMDBUF_ALIGNMENT_SIZE >> 3) - - ((dev_priv->dma_low & CMDBUF_ALIGNMENT_MASK) >> 3); - - cmd_addr = (addr) ? addr : - agp_base + dev_priv->dma_low - 8 + (qw_pad_count << 3); - addr_lo = ((HC_SubA_HAGPBpL << 24) | (cmd_type & HC_HAGPBpID_MASK) | - (cmd_addr & HC_HAGPBpL_MASK)); - addr_hi = ((HC_SubA_HAGPBpH << 24) | (cmd_addr >> 24)); - - vb = via_align_buffer(dev_priv, vb, qw_pad_count - 1); - VIA_OUT_RING_QW(*cmd_addr_hi = addr_hi, *cmd_addr_lo = addr_lo); - return vb; -} - -static void via_cmdbuf_start(drm_via_private_t *dev_priv) -{ - uint32_t pause_addr_lo, pause_addr_hi; - uint32_t start_addr, start_addr_lo; - uint32_t end_addr, end_addr_lo; - uint32_t command; - uint32_t agp_base; - uint32_t ptr; - uint32_t reader; - int count; - - dev_priv->dma_low = 0; - - agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; - start_addr = agp_base; - end_addr = agp_base + dev_priv->dma_high; - - start_addr_lo = ((HC_SubA_HAGPBstL << 24) | (start_addr & 0xFFFFFF)); - end_addr_lo = ((HC_SubA_HAGPBendL << 24) | (end_addr & 0xFFFFFF)); - command = ((HC_SubA_HAGPCMNT << 24) | (start_addr >> 24) | - ((end_addr & 0xff000000) >> 16)); - - dev_priv->last_pause_ptr = - via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, - &pause_addr_hi, &pause_addr_lo, 1) - 1; - - via_flush_write_combine(); - (void) *(volatile uint32_t *)dev_priv->last_pause_ptr; - - via_write(dev_priv, VIA_REG_TRANSET, (HC_ParaType_PreCR << 16)); - via_write(dev_priv, VIA_REG_TRANSPACE, command); - via_write(dev_priv, VIA_REG_TRANSPACE, start_addr_lo); - via_write(dev_priv, VIA_REG_TRANSPACE, end_addr_lo); - - via_write(dev_priv, VIA_REG_TRANSPACE, pause_addr_hi); - via_write(dev_priv, VIA_REG_TRANSPACE, pause_addr_lo); - wmb(); - via_write(dev_priv, VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK); - via_read(dev_priv, VIA_REG_TRANSPACE); - - dev_priv->dma_diff = 0; - - count = 10000000; - while (!(via_read(dev_priv, 0x41c) & 0x80000000) && count--); - - reader = *(dev_priv->hw_addr_ptr); - ptr = ((volatile char *)dev_priv->last_pause_ptr - dev_priv->dma_ptr) + - dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4; - - /* - * This is the difference between where we tell the - * command reader to pause and where it actually pauses. - * This differs between hw implementation so we need to - * detect it. - */ - - dev_priv->dma_diff = ptr - reader; -} - -static void via_pad_cache(drm_via_private_t *dev_priv, int qwords) -{ - uint32_t *vb; - - via_cmdbuf_wait(dev_priv, qwords + 2); - vb = via_get_dma(dev_priv); - VIA_OUT_RING_QW(HC_HEADER2, HC_ParaType_NotTex << 16); - via_align_buffer(dev_priv, vb, qwords); -} - -static inline void via_dummy_bitblt(drm_via_private_t *dev_priv) -{ - uint32_t *vb = via_get_dma(dev_priv); - SetReg2DAGP(0x0C, (0 | (0 << 16))); - SetReg2DAGP(0x10, 0 | (0 << 16)); - SetReg2DAGP(0x0, 0x1 | 0x2000 | 0xAA000000); -} - -static void via_cmdbuf_jump(drm_via_private_t *dev_priv) -{ - uint32_t pause_addr_lo, pause_addr_hi; - uint32_t jump_addr_lo, jump_addr_hi; - volatile uint32_t *last_pause_ptr; - uint32_t dma_low_save1, dma_low_save2; - - via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi, - &jump_addr_lo, 0); - - dev_priv->dma_wrap = dev_priv->dma_low; - - /* - * Wrap command buffer to the beginning. - */ - - dev_priv->dma_low = 0; - if (via_cmdbuf_wait(dev_priv, CMDBUF_ALIGNMENT_SIZE) != 0) - DRM_ERROR("via_cmdbuf_jump failed\n"); - - via_dummy_bitblt(dev_priv); - via_dummy_bitblt(dev_priv); - - last_pause_ptr = - via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, - &pause_addr_lo, 0) - 1; - via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, - &pause_addr_lo, 0); - - *last_pause_ptr = pause_addr_lo; - dma_low_save1 = dev_priv->dma_low; - - /* - * Now, set a trap that will pause the regulator if it tries to rerun the old - * command buffer. (Which may happen if via_hook_segment detecs a command regulator pause - * and reissues the jump command over PCI, while the regulator has already taken the jump - * and actually paused at the current buffer end). - * There appears to be no other way to detect this condition, since the hw_addr_pointer - * does not seem to get updated immediately when a jump occurs. - */ - - last_pause_ptr = - via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, - &pause_addr_lo, 0) - 1; - via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, - &pause_addr_lo, 0); - *last_pause_ptr = pause_addr_lo; - - dma_low_save2 = dev_priv->dma_low; - dev_priv->dma_low = dma_low_save1; - via_hook_segment(dev_priv, jump_addr_hi, jump_addr_lo, 0); - dev_priv->dma_low = dma_low_save2; - via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0); -} - - -static void via_cmdbuf_rewind(drm_via_private_t *dev_priv) -{ - via_cmdbuf_jump(dev_priv); -} - -static void via_cmdbuf_flush(drm_via_private_t *dev_priv, uint32_t cmd_type) -{ - uint32_t pause_addr_lo, pause_addr_hi; - - via_align_cmd(dev_priv, cmd_type, 0, &pause_addr_hi, &pause_addr_lo, 0); - via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0); -} - -static void via_cmdbuf_pause(drm_via_private_t *dev_priv) -{ - via_cmdbuf_flush(dev_priv, HC_HAGPBpID_PAUSE); -} - -static void via_cmdbuf_reset(drm_via_private_t *dev_priv) -{ - via_cmdbuf_flush(dev_priv, HC_HAGPBpID_STOP); - via_wait_idle(dev_priv); -} - -/* - * User interface to the space and lag functions. - */ - -static int via_cmdbuf_size(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - drm_via_cmdbuf_size_t *d_siz = data; - int ret = 0; - uint32_t tmp_size, count; - drm_via_private_t *dev_priv; - - DRM_DEBUG("\n"); - LOCK_TEST_WITH_RETURN(dev, file_priv); - - dev_priv = (drm_via_private_t *) dev->dev_private; - - if (dev_priv->ring.virtual_start == NULL) { - DRM_ERROR("called without initializing AGP ring buffer.\n"); - return -EFAULT; - } - - count = 1000000; - tmp_size = d_siz->size; - switch (d_siz->func) { - case VIA_CMDBUF_SPACE: - while (((tmp_size = via_cmdbuf_space(dev_priv)) < d_siz->size) - && --count) { - if (!d_siz->wait) - break; - } - if (!count) { - DRM_ERROR("VIA_CMDBUF_SPACE timed out.\n"); - ret = -EAGAIN; - } - break; - case VIA_CMDBUF_LAG: - while (((tmp_size = via_cmdbuf_lag(dev_priv)) > d_siz->size) - && --count) { - if (!d_siz->wait) - break; - } - if (!count) { - DRM_ERROR("VIA_CMDBUF_LAG timed out.\n"); - ret = -EAGAIN; - } - break; - default: - ret = -EFAULT; - } - d_siz->size = tmp_size; - - return ret; -} - -const struct drm_ioctl_desc via_ioctls[] = { - DRM_IOCTL_DEF_DRV(VIA_ALLOCMEM, via_mem_alloc, DRM_AUTH), - DRM_IOCTL_DEF_DRV(VIA_FREEMEM, via_mem_free, DRM_AUTH), - DRM_IOCTL_DEF_DRV(VIA_AGP_INIT, via_agp_init, DRM_AUTH|DRM_MASTER), - DRM_IOCTL_DEF_DRV(VIA_FB_INIT, via_fb_init, DRM_AUTH|DRM_MASTER), - DRM_IOCTL_DEF_DRV(VIA_MAP_INIT, via_map_init, DRM_AUTH|DRM_MASTER), - DRM_IOCTL_DEF_DRV(VIA_DEC_FUTEX, via_decoder_futex, DRM_AUTH), - DRM_IOCTL_DEF_DRV(VIA_DMA_INIT, via_dma_init, DRM_AUTH), - DRM_IOCTL_DEF_DRV(VIA_CMDBUFFER, via_cmdbuffer, DRM_AUTH), - DRM_IOCTL_DEF_DRV(VIA_FLUSH, via_flush_ioctl, DRM_AUTH), - DRM_IOCTL_DEF_DRV(VIA_PCICMD, via_pci_cmdbuffer, DRM_AUTH), - DRM_IOCTL_DEF_DRV(VIA_CMDBUF_SIZE, via_cmdbuf_size, DRM_AUTH), - DRM_IOCTL_DEF_DRV(VIA_WAIT_IRQ, via_wait_irq, DRM_AUTH), - DRM_IOCTL_DEF_DRV(VIA_DMA_BLIT, via_dma_blit, DRM_AUTH), - DRM_IOCTL_DEF_DRV(VIA_BLIT_SYNC, via_dma_blit_sync, DRM_AUTH) -}; - -int via_max_ioctl = ARRAY_SIZE(via_ioctls); diff --git a/drivers/gpu/drm/via/via_dmablit.c b/drivers/gpu/drm/via/via_dmablit.c deleted file mode 100644 index e016a4d62090..000000000000 --- a/drivers/gpu/drm/via/via_dmablit.c +++ /dev/null @@ -1,807 +0,0 @@ -/* via_dmablit.c -- PCI DMA BitBlt support for the VIA Unichrome/Pro - * - * Copyright (C) 2005 Thomas Hellstrom, All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sub license, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: - * Thomas Hellstrom. - * Partially based on code obtained from Digeo Inc. - */ - - -/* - * Unmaps the DMA mappings. - * FIXME: Is this a NoOp on x86? Also - * FIXME: What happens if this one is called and a pending blit has previously done - * the same DMA mappings? - */ - -#include <linux/pagemap.h> -#include <linux/pci.h> -#include <linux/slab.h> -#include <linux/vmalloc.h> - -#include <drm/drm_device.h> -#include <drm/via_drm.h> - -#include "via_dmablit.h" -#include "via_drv.h" - -#define VIA_PGDN(x) (((unsigned long)(x)) & PAGE_MASK) -#define VIA_PGOFF(x) (((unsigned long)(x)) & ~PAGE_MASK) -#define VIA_PFN(x) ((unsigned long)(x) >> PAGE_SHIFT) - -typedef struct _drm_via_descriptor { - uint32_t mem_addr; - uint32_t dev_addr; - uint32_t size; - uint32_t next; -} drm_via_descriptor_t; - - -/* - * Unmap a DMA mapping. - */ - - - -static void -via_unmap_blit_from_device(struct pci_dev *pdev, drm_via_sg_info_t *vsg) -{ - int num_desc = vsg->num_desc; - unsigned cur_descriptor_page = num_desc / vsg->descriptors_per_page; - unsigned descriptor_this_page = num_desc % vsg->descriptors_per_page; - drm_via_descriptor_t *desc_ptr = vsg->desc_pages[cur_descriptor_page] + - descriptor_this_page; - dma_addr_t next = vsg->chain_start; - - while (num_desc--) { - if (descriptor_this_page-- == 0) { - cur_descriptor_page--; - descriptor_this_page = vsg->descriptors_per_page - 1; - desc_ptr = vsg->desc_pages[cur_descriptor_page] + - descriptor_this_page; - } - dma_unmap_single(&pdev->dev, next, sizeof(*desc_ptr), DMA_TO_DEVICE); - dma_unmap_page(&pdev->dev, desc_ptr->mem_addr, desc_ptr->size, vsg->direction); - next = (dma_addr_t) desc_ptr->next; - desc_ptr--; - } -} - -/* - * If mode = 0, count how many descriptors are needed. - * If mode = 1, Map the DMA pages for the device, put together and map also the descriptors. - * Descriptors are run in reverse order by the hardware because we are not allowed to update the - * 'next' field without syncing calls when the descriptor is already mapped. - */ - -static void -via_map_blit_for_device(struct pci_dev *pdev, - const drm_via_dmablit_t *xfer, - drm_via_sg_info_t *vsg, - int mode) -{ - unsigned cur_descriptor_page = 0; - unsigned num_descriptors_this_page = 0; - unsigned char *mem_addr = xfer->mem_addr; - unsigned char *cur_mem; - unsigned char *first_addr = (unsigned char *)VIA_PGDN(mem_addr); - uint32_t fb_addr = xfer->fb_addr; - uint32_t cur_fb; - unsigned long line_len; - unsigned remaining_len; - int num_desc = 0; - int cur_line; - dma_addr_t next = 0 | VIA_DMA_DPR_EC; - drm_via_descriptor_t *desc_ptr = NULL; - - if (mode == 1) - desc_ptr = vsg->desc_pages[cur_descriptor_page]; - - for (cur_line = 0; cur_line < xfer->num_lines; ++cur_line) { - - line_len = xfer->line_length; - cur_fb = fb_addr; - cur_mem = mem_addr; - - while (line_len > 0) { - - remaining_len = min(PAGE_SIZE-VIA_PGOFF(cur_mem), line_len); - line_len -= remaining_len; - - if (mode == 1) { - desc_ptr->mem_addr = - dma_map_page(&pdev->dev, - vsg->pages[VIA_PFN(cur_mem) - - VIA_PFN(first_addr)], - VIA_PGOFF(cur_mem), remaining_len, - vsg->direction); - desc_ptr->dev_addr = cur_fb; - - desc_ptr->size = remaining_len; - desc_ptr->next = (uint32_t) next; - next = dma_map_single(&pdev->dev, desc_ptr, sizeof(*desc_ptr), - DMA_TO_DEVICE); - desc_ptr++; - if (++num_descriptors_this_page >= vsg->descriptors_per_page) { - num_descriptors_this_page = 0; - desc_ptr = vsg->desc_pages[++cur_descriptor_page]; - } - } - - num_desc++; - cur_mem += remaining_len; - cur_fb += remaining_len; - } - - mem_addr += xfer->mem_stride; - fb_addr += xfer->fb_stride; - } - - if (mode == 1) { - vsg->chain_start = next; - vsg->state = dr_via_device_mapped; - } - vsg->num_desc = num_desc; -} - -/* - * Function that frees up all resources for a blit. It is usable even if the - * blit info has only been partially built as long as the status enum is consistent - * with the actual status of the used resources. - */ - - -static void -via_free_sg_info(struct pci_dev *pdev, drm_via_sg_info_t *vsg) -{ - int i; - - switch (vsg->state) { - case dr_via_device_mapped: - via_unmap_blit_from_device(pdev, vsg); - fallthrough; - case dr_via_desc_pages_alloc: - for (i = 0; i < vsg->num_desc_pages; ++i) { - if (vsg->desc_pages[i] != NULL) - free_page((unsigned long)vsg->desc_pages[i]); - } - kfree(vsg->desc_pages); - fallthrough; - case dr_via_pages_locked: - unpin_user_pages_dirty_lock(vsg->pages, vsg->num_pages, - (vsg->direction == DMA_FROM_DEVICE)); - fallthrough; - case dr_via_pages_alloc: - vfree(vsg->pages); - fallthrough; - default: - vsg->state = dr_via_sg_init; - } - vfree(vsg->bounce_buffer); - vsg->bounce_buffer = NULL; - vsg->free_on_sequence = 0; -} - -/* - * Fire a blit engine. - */ - -static void -via_fire_dmablit(struct drm_device *dev, drm_via_sg_info_t *vsg, int engine) -{ - drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; - - via_write(dev_priv, VIA_PCI_DMA_MAR0 + engine*0x10, 0); - via_write(dev_priv, VIA_PCI_DMA_DAR0 + engine*0x10, 0); - via_write(dev_priv, VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_DD | VIA_DMA_CSR_TD | - VIA_DMA_CSR_DE); - via_write(dev_priv, VIA_PCI_DMA_MR0 + engine*0x04, VIA_DMA_MR_CM | VIA_DMA_MR_TDIE); - via_write(dev_priv, VIA_PCI_DMA_BCR0 + engine*0x10, 0); - via_write(dev_priv, VIA_PCI_DMA_DPR0 + engine*0x10, vsg->chain_start); - wmb(); - via_write(dev_priv, VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_DE | VIA_DMA_CSR_TS); - via_read(dev_priv, VIA_PCI_DMA_CSR0 + engine*0x04); -} - -/* - * Obtain a page pointer array and lock all pages into system memory. A segmentation violation will - * occur here if the calling user does not have access to the submitted address. - */ - -static int -via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer) -{ - int ret; - unsigned long first_pfn = VIA_PFN(xfer->mem_addr); - vsg->num_pages = VIA_PFN(xfer->mem_addr + (xfer->num_lines * xfer->mem_stride - 1)) - - first_pfn + 1; - - vsg->pages = vzalloc(array_size(sizeof(struct page *), vsg->num_pages)); - if (NULL == vsg->pages) - return -ENOMEM; - ret = pin_user_pages_fast((unsigned long)xfer->mem_addr, - vsg->num_pages, - vsg->direction == DMA_FROM_DEVICE ? FOLL_WRITE : 0, - vsg->pages); - if (ret != vsg->num_pages) { - if (ret < 0) - return ret; - vsg->state = dr_via_pages_locked; - return -EINVAL; - } - vsg->state = dr_via_pages_locked; - DRM_DEBUG("DMA pages locked\n"); - return 0; -} - -/* - * Allocate DMA capable memory for the blit descriptor chain, and an array that keeps track of the - * pages we allocate. We don't want to use kmalloc for the descriptor chain because it may be - * quite large for some blits, and pages don't need to be contiguous. - */ - -static int -via_alloc_desc_pages(drm_via_sg_info_t *vsg) -{ - int i; - - vsg->descriptors_per_page = PAGE_SIZE / sizeof(drm_via_descriptor_t); - vsg->num_desc_pages = (vsg->num_desc + vsg->descriptors_per_page - 1) / - vsg->descriptors_per_page; - - if (NULL == (vsg->desc_pages = kcalloc(vsg->num_desc_pages, sizeof(void *), GFP_KERNEL))) - return -ENOMEM; - - vsg->state = dr_via_desc_pages_alloc; - for (i = 0; i < vsg->num_desc_pages; ++i) { - if (NULL == (vsg->desc_pages[i] = - (drm_via_descriptor_t *) __get_free_page(GFP_KERNEL))) - return -ENOMEM; - } - DRM_DEBUG("Allocated %d pages for %d descriptors.\n", vsg->num_desc_pages, - vsg->num_desc); - return 0; -} - -static void -via_abort_dmablit(struct drm_device *dev, int engine) -{ - drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; - - via_write(dev_priv, VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_TA); -} - -static void -via_dmablit_engine_off(struct drm_device *dev, int engine) -{ - drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; - - via_write(dev_priv, VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_TD | VIA_DMA_CSR_DD); -} - - - -/* - * The dmablit part of the IRQ handler. Trying to do only reasonably fast things here. - * The rest, like unmapping and freeing memory for done blits is done in a separate workqueue - * task. Basically the task of the interrupt handler is to submit a new blit to the engine, while - * the workqueue task takes care of processing associated with the old blit. - */ - -void -via_dmablit_handler(struct drm_device *dev, int engine, int from_irq) -{ - drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; - drm_via_blitq_t *blitq = dev_priv->blit_queues + engine; - int cur; - int done_transfer; - unsigned long irqsave = 0; - uint32_t status = 0; - - DRM_DEBUG("DMA blit handler called. engine = %d, from_irq = %d, blitq = 0x%lx\n", - engine, from_irq, (unsigned long) blitq); - - if (from_irq) - spin_lock(&blitq->blit_lock); - else - spin_lock_irqsave(&blitq->blit_lock, irqsave); - - done_transfer = blitq->is_active && - ((status = via_read(dev_priv, VIA_PCI_DMA_CSR0 + engine*0x04)) & VIA_DMA_CSR_TD); - done_transfer = done_transfer || (blitq->aborting && !(status & VIA_DMA_CSR_DE)); - - cur = blitq->cur; - if (done_transfer) { - - blitq->blits[cur]->aborted = blitq->aborting; - blitq->done_blit_handle++; - wake_up(blitq->blit_queue + cur); - - cur++; - if (cur >= VIA_NUM_BLIT_SLOTS) - cur = 0; - blitq->cur = cur; - - /* - * Clear transfer done flag. - */ - - via_write(dev_priv, VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_TD); - - blitq->is_active = 0; - blitq->aborting = 0; - schedule_work(&blitq->wq); - - } else if (blitq->is_active && time_after_eq(jiffies, blitq->end)) { - - /* - * Abort transfer after one second. - */ - - via_abort_dmablit(dev, engine); - blitq->aborting = 1; - blitq->end = jiffies + HZ; - } - - if (!blitq->is_active) { - if (blitq->num_outstanding) { - via_fire_dmablit(dev, blitq->blits[cur], engine); - blitq->is_active = 1; - blitq->cur = cur; - blitq->num_outstanding--; - blitq->end = jiffies + HZ; - if (!timer_pending(&blitq->poll_timer)) - mod_timer(&blitq->poll_timer, jiffies + 1); - } else { - if (timer_pending(&blitq->poll_timer)) - del_timer(&blitq->poll_timer); - via_dmablit_engine_off(dev, engine); - } - } - - if (from_irq) - spin_unlock(&blitq->blit_lock); - else - spin_unlock_irqrestore(&blitq->blit_lock, irqsave); -} - - - -/* - * Check whether this blit is still active, performing necessary locking. - */ - -static int -via_dmablit_active(drm_via_blitq_t *blitq, int engine, uint32_t handle, wait_queue_head_t **queue) -{ - unsigned long irqsave; - uint32_t slot; - int active; - - spin_lock_irqsave(&blitq->blit_lock, irqsave); - - /* - * Allow for handle wraparounds. - */ - - active = ((blitq->done_blit_handle - handle) > (1 << 23)) && - ((blitq->cur_blit_handle - handle) <= (1 << 23)); - - if (queue && active) { - slot = handle - blitq->done_blit_handle + blitq->cur - 1; - if (slot >= VIA_NUM_BLIT_SLOTS) - slot -= VIA_NUM_BLIT_SLOTS; - *queue = blitq->blit_queue + slot; - } - - spin_unlock_irqrestore(&blitq->blit_lock, irqsave); - - return active; -} - -/* - * Sync. Wait for at least three seconds for the blit to be performed. - */ - -static int -via_dmablit_sync(struct drm_device *dev, uint32_t handle, int engine) -{ - - drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; - drm_via_blitq_t *blitq = dev_priv->blit_queues + engine; - wait_queue_head_t *queue; - int ret = 0; - - if (via_dmablit_active(blitq, engine, handle, &queue)) { - VIA_WAIT_ON(ret, *queue, 3 * HZ, - !via_dmablit_active(blitq, engine, handle, NULL)); - } - DRM_DEBUG("DMA blit sync handle 0x%x engine %d returned %d\n", - handle, engine, ret); - - return ret; -} - - -/* - * A timer that regularly polls the blit engine in cases where we don't have interrupts: - * a) Broken hardware (typically those that don't have any video capture facility). - * b) Blit abort. The hardware doesn't send an interrupt when a blit is aborted. - * The timer and hardware IRQ's can and do work in parallel. If the hardware has - * irqs, it will shorten the latency somewhat. - */ - - - -static void -via_dmablit_timer(struct timer_list *t) -{ - drm_via_blitq_t *blitq = from_timer(blitq, t, poll_timer); - struct drm_device *dev = blitq->dev; - int engine = (int) - (blitq - ((drm_via_private_t *)dev->dev_private)->blit_queues); - - DRM_DEBUG("Polling timer called for engine %d, jiffies %lu\n", engine, - (unsigned long) jiffies); - - via_dmablit_handler(dev, engine, 0); - - if (!timer_pending(&blitq->poll_timer)) { - mod_timer(&blitq->poll_timer, jiffies + 1); - - /* - * Rerun handler to delete timer if engines are off, and - * to shorten abort latency. This is a little nasty. - */ - - via_dmablit_handler(dev, engine, 0); - - } -} - - - - -/* - * Workqueue task that frees data and mappings associated with a blit. - * Also wakes up waiting processes. Each of these tasks handles one - * blit engine only and may not be called on each interrupt. - */ - - -static void -via_dmablit_workqueue(struct work_struct *work) -{ - drm_via_blitq_t *blitq = container_of(work, drm_via_blitq_t, wq); - struct drm_device *dev = blitq->dev; - struct pci_dev *pdev = to_pci_dev(dev->dev); - unsigned long irqsave; - drm_via_sg_info_t *cur_sg; - int cur_released; - - - DRM_DEBUG("Workqueue task called for blit engine %ld\n", (unsigned long) - (blitq - ((drm_via_private_t *)dev->dev_private)->blit_queues)); - - spin_lock_irqsave(&blitq->blit_lock, irqsave); - - while (blitq->serviced != blitq->cur) { - - cur_released = blitq->serviced++; - - DRM_DEBUG("Releasing blit slot %d\n", cur_released); - - if (blitq->serviced >= VIA_NUM_BLIT_SLOTS) - blitq->serviced = 0; - - cur_sg = blitq->blits[cur_released]; - blitq->num_free++; - - spin_unlock_irqrestore(&blitq->blit_lock, irqsave); - - wake_up(&blitq->busy_queue); - - via_free_sg_info(pdev, cur_sg); - kfree(cur_sg); - - spin_lock_irqsave(&blitq->blit_lock, irqsave); - } - - spin_unlock_irqrestore(&blitq->blit_lock, irqsave); -} - - -/* - * Init all blit engines. Currently we use two, but some hardware have 4. - */ - - -void -via_init_dmablit(struct drm_device *dev) -{ - int i, j; - drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; - struct pci_dev *pdev = to_pci_dev(dev->dev); - drm_via_blitq_t *blitq; - - pci_set_master(pdev); - - for (i = 0; i < VIA_NUM_BLIT_ENGINES; ++i) { - blitq = dev_priv->blit_queues + i; - blitq->dev = dev; - blitq->cur_blit_handle = 0; - blitq->done_blit_handle = 0; - blitq->head = 0; - blitq->cur = 0; - blitq->serviced = 0; - blitq->num_free = VIA_NUM_BLIT_SLOTS - 1; - blitq->num_outstanding = 0; - blitq->is_active = 0; - blitq->aborting = 0; - spin_lock_init(&blitq->blit_lock); - for (j = 0; j < VIA_NUM_BLIT_SLOTS; ++j) - init_waitqueue_head(blitq->blit_queue + j); - init_waitqueue_head(&blitq->busy_queue); - INIT_WORK(&blitq->wq, via_dmablit_workqueue); - timer_setup(&blitq->poll_timer, via_dmablit_timer, 0); - } -} - -/* - * Build all info and do all mappings required for a blit. - */ - - -static int -via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer) -{ - struct pci_dev *pdev = to_pci_dev(dev->dev); - int draw = xfer->to_fb; - int ret = 0; - - vsg->direction = (draw) ? DMA_TO_DEVICE : DMA_FROM_DEVICE; - vsg->bounce_buffer = NULL; - - vsg->state = dr_via_sg_init; - - if (xfer->num_lines <= 0 || xfer->line_length <= 0) { - DRM_ERROR("Zero size bitblt.\n"); - return -EINVAL; - } - - /* - * Below check is a driver limitation, not a hardware one. We - * don't want to lock unused pages, and don't want to incoporate the - * extra logic of avoiding them. Make sure there are no. - * (Not a big limitation anyway.) - */ - - if ((xfer->mem_stride - xfer->line_length) > 2*PAGE_SIZE) { - DRM_ERROR("Too large system memory stride. Stride: %d, " - "Length: %d\n", xfer->mem_stride, xfer->line_length); - return -EINVAL; - } - - if ((xfer->mem_stride == xfer->line_length) && - (xfer->fb_stride == xfer->line_length)) { - xfer->mem_stride *= xfer->num_lines; - xfer->line_length = xfer->mem_stride; - xfer->fb_stride = xfer->mem_stride; - xfer->num_lines = 1; - } - - /* - * Don't lock an arbitrary large number of pages, since that causes a - * DOS security hole. - */ - - if (xfer->num_lines > 2048 || (xfer->num_lines*xfer->mem_stride > (2048*2048*4))) { - DRM_ERROR("Too large PCI DMA bitblt.\n"); - return -EINVAL; - } - - /* - * we allow a negative fb stride to allow flipping of images in - * transfer. - */ - - if (xfer->mem_stride < xfer->line_length || - abs(xfer->fb_stride) < xfer->line_length) { - DRM_ERROR("Invalid frame-buffer / memory stride.\n"); - return -EINVAL; - } - - /* - * A hardware bug seems to be worked around if system memory addresses start on - * 16 byte boundaries. This seems a bit restrictive however. VIA is contacted - * about this. Meanwhile, impose the following restrictions: - */ - -#ifdef VIA_BUGFREE - if ((((unsigned long)xfer->mem_addr & 3) != ((unsigned long)xfer->fb_addr & 3)) || - ((xfer->num_lines > 1) && ((xfer->mem_stride & 3) != (xfer->fb_stride & 3)))) { - DRM_ERROR("Invalid DRM bitblt alignment.\n"); - return -EINVAL; - } -#else - if ((((unsigned long)xfer->mem_addr & 15) || - ((unsigned long)xfer->fb_addr & 3)) || - ((xfer->num_lines > 1) && - ((xfer->mem_stride & 15) || (xfer->fb_stride & 3)))) { - DRM_ERROR("Invalid DRM bitblt alignment.\n"); - return -EINVAL; - } -#endif - - if (0 != (ret = via_lock_all_dma_pages(vsg, xfer))) { - DRM_ERROR("Could not lock DMA pages.\n"); - via_free_sg_info(pdev, vsg); - return ret; - } - - via_map_blit_for_device(pdev, xfer, vsg, 0); - if (0 != (ret = via_alloc_desc_pages(vsg))) { - DRM_ERROR("Could not allocate DMA descriptor pages.\n"); - via_free_sg_info(pdev, vsg); - return ret; - } - via_map_blit_for_device(pdev, xfer, vsg, 1); - - return 0; -} - - -/* - * Reserve one free slot in the blit queue. Will wait for one second for one - * to become available. Otherwise -EBUSY is returned. - */ - -static int -via_dmablit_grab_slot(drm_via_blitq_t *blitq, int engine) -{ - int ret = 0; - unsigned long irqsave; - - DRM_DEBUG("Num free is %d\n", blitq->num_free); - spin_lock_irqsave(&blitq->blit_lock, irqsave); - while (blitq->num_free == 0) { - spin_unlock_irqrestore(&blitq->blit_lock, irqsave); - - VIA_WAIT_ON(ret, blitq->busy_queue, HZ, blitq->num_free > 0); - if (ret) - return (-EINTR == ret) ? -EAGAIN : ret; - - spin_lock_irqsave(&blitq->blit_lock, irqsave); - } - - blitq->num_free--; - spin_unlock_irqrestore(&blitq->blit_lock, irqsave); - - return 0; -} - -/* - * Hand back a free slot if we changed our mind. - */ - -static void -via_dmablit_release_slot(drm_via_blitq_t *blitq) -{ - unsigned long irqsave; - - spin_lock_irqsave(&blitq->blit_lock, irqsave); - blitq->num_free++; - spin_unlock_irqrestore(&blitq->blit_lock, irqsave); - wake_up(&blitq->busy_queue); -} - -/* - * Grab a free slot. Build blit info and queue a blit. - */ - - -static int -via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer) -{ - drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; - drm_via_sg_info_t *vsg; - drm_via_blitq_t *blitq; - int ret; - int engine; - unsigned long irqsave; - - if (dev_priv == NULL) { - DRM_ERROR("Called without initialization.\n"); - return -EINVAL; - } - - engine = (xfer->to_fb) ? 0 : 1; - blitq = dev_priv->blit_queues + engine; - if (0 != (ret = via_dmablit_grab_slot(blitq, engine))) - return ret; - if (NULL == (vsg = kmalloc(sizeof(*vsg), GFP_KERNEL))) { - via_dmablit_release_slot(blitq); - return -ENOMEM; - } - if (0 != (ret = via_build_sg_info(dev, vsg, xfer))) { - via_dmablit_release_slot(blitq); - kfree(vsg); - return ret; - } - spin_lock_irqsave(&blitq->blit_lock, irqsave); - - blitq->blits[blitq->head++] = vsg; - if (blitq->head >= VIA_NUM_BLIT_SLOTS) - blitq->head = 0; - blitq->num_outstanding++; - xfer->sync.sync_handle = ++blitq->cur_blit_handle; - - spin_unlock_irqrestore(&blitq->blit_lock, irqsave); - xfer->sync.engine = engine; - - via_dmablit_handler(dev, engine, 0); - - return 0; -} - -/* - * Sync on a previously submitted blit. Note that the X server use signals extensively, and - * that there is a very big probability that this IOCTL will be interrupted by a signal. In that - * case it returns with -EAGAIN for the signal to be delivered. - * The caller should then reissue the IOCTL. This is similar to what is being done for drmGetLock(). - */ - -int -via_dma_blit_sync(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - drm_via_blitsync_t *sync = data; - int err; - - if (sync->engine >= VIA_NUM_BLIT_ENGINES) - return -EINVAL; - - err = via_dmablit_sync(dev, sync->sync_handle, sync->engine); - - if (-EINTR == err) - err = -EAGAIN; - - return err; -} - - -/* - * Queue a blit and hand back a handle to be used for sync. This IOCTL may be interrupted by a signal - * while waiting for a free slot in the blit queue. In that case it returns with -EAGAIN and should - * be reissued. See the above IOCTL code. - */ - -int -via_dma_blit(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - drm_via_dmablit_t *xfer = data; - int err; - - err = via_dmablit(dev, xfer); - - return err; -} diff --git a/drivers/gpu/drm/via/via_dmablit.h b/drivers/gpu/drm/via/via_dmablit.h deleted file mode 100644 index 9b662a327cef..000000000000 --- a/drivers/gpu/drm/via/via_dmablit.h +++ /dev/null @@ -1,140 +0,0 @@ -/* via_dmablit.h -- PCI DMA BitBlt support for the VIA Unichrome/Pro - * - * Copyright 2005 Thomas Hellstrom. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sub license, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: - * Thomas Hellstrom. - * Register info from Digeo Inc. - */ - -#ifndef _VIA_DMABLIT_H -#define _VIA_DMABLIT_H - -#include <linux/dma-mapping.h> - -#define VIA_NUM_BLIT_ENGINES 2 -#define VIA_NUM_BLIT_SLOTS 8 - -struct _drm_via_descriptor; - -typedef struct _drm_via_sg_info { - struct page **pages; - unsigned long num_pages; - struct _drm_via_descriptor **desc_pages; - int num_desc_pages; - int num_desc; - enum dma_data_direction direction; - unsigned char *bounce_buffer; - dma_addr_t chain_start; - uint32_t free_on_sequence; - unsigned int descriptors_per_page; - int aborted; - enum { - dr_via_device_mapped, - dr_via_desc_pages_alloc, - dr_via_pages_locked, - dr_via_pages_alloc, - dr_via_sg_init - } state; -} drm_via_sg_info_t; - -typedef struct _drm_via_blitq { - struct drm_device *dev; - uint32_t cur_blit_handle; - uint32_t done_blit_handle; - unsigned serviced; - unsigned head; - unsigned cur; - unsigned num_free; - unsigned num_outstanding; - unsigned long end; - int aborting; - int is_active; - drm_via_sg_info_t *blits[VIA_NUM_BLIT_SLOTS]; - spinlock_t blit_lock; - wait_queue_head_t blit_queue[VIA_NUM_BLIT_SLOTS]; - wait_queue_head_t busy_queue; - struct work_struct wq; - struct timer_list poll_timer; -} drm_via_blitq_t; - - -/* - * PCI DMA Registers - * Channels 2 & 3 don't seem to be implemented in hardware. - */ - -#define VIA_PCI_DMA_MAR0 0xE40 /* Memory Address Register of Channel 0 */ -#define VIA_PCI_DMA_DAR0 0xE44 /* Device Address Register of Channel 0 */ -#define VIA_PCI_DMA_BCR0 0xE48 /* Byte Count Register of Channel 0 */ -#define VIA_PCI_DMA_DPR0 0xE4C /* Descriptor Pointer Register of Channel 0 */ - -#define VIA_PCI_DMA_MAR1 0xE50 /* Memory Address Register of Channel 1 */ -#define VIA_PCI_DMA_DAR1 0xE54 /* Device Address Register of Channel 1 */ -#define VIA_PCI_DMA_BCR1 0xE58 /* Byte Count Register of Channel 1 */ -#define VIA_PCI_DMA_DPR1 0xE5C /* Descriptor Pointer Register of Channel 1 */ - -#define VIA_PCI_DMA_MAR2 0xE60 /* Memory Address Register of Channel 2 */ -#define VIA_PCI_DMA_DAR2 0xE64 /* Device Address Register of Channel 2 */ -#define VIA_PCI_DMA_BCR2 0xE68 /* Byte Count Register of Channel 2 */ -#define VIA_PCI_DMA_DPR2 0xE6C /* Descriptor Pointer Register of Channel 2 */ - -#define VIA_PCI_DMA_MAR3 0xE70 /* Memory Address Register of Channel 3 */ -#define VIA_PCI_DMA_DAR3 0xE74 /* Device Address Register of Channel 3 */ -#define VIA_PCI_DMA_BCR3 0xE78 /* Byte Count Register of Channel 3 */ -#define VIA_PCI_DMA_DPR3 0xE7C /* Descriptor Pointer Register of Channel 3 */ - -#define VIA_PCI_DMA_MR0 0xE80 /* Mode Register of Channel 0 */ -#define VIA_PCI_DMA_MR1 0xE84 /* Mode Register of Channel 1 */ -#define VIA_PCI_DMA_MR2 0xE88 /* Mode Register of Channel 2 */ -#define VIA_PCI_DMA_MR3 0xE8C /* Mode Register of Channel 3 */ - -#define VIA_PCI_DMA_CSR0 0xE90 /* Command/Status Register of Channel 0 */ -#define VIA_PCI_DMA_CSR1 0xE94 /* Command/Status Register of Channel 1 */ -#define VIA_PCI_DMA_CSR2 0xE98 /* Command/Status Register of Channel 2 */ -#define VIA_PCI_DMA_CSR3 0xE9C /* Command/Status Register of Channel 3 */ - -#define VIA_PCI_DMA_PTR 0xEA0 /* Priority Type Register */ - -/* Define for DMA engine */ -/* DPR */ -#define VIA_DMA_DPR_EC (1<<1) /* end of chain */ -#define VIA_DMA_DPR_DDIE (1<<2) /* descriptor done interrupt enable */ -#define VIA_DMA_DPR_DT (1<<3) /* direction of transfer (RO) */ - -/* MR */ -#define VIA_DMA_MR_CM (1<<0) /* chaining mode */ -#define VIA_DMA_MR_TDIE (1<<1) /* transfer done interrupt enable */ -#define VIA_DMA_MR_HENDMACMD (1<<7) /* ? */ - -/* CSR */ -#define VIA_DMA_CSR_DE (1<<0) /* DMA enable */ -#define VIA_DMA_CSR_TS (1<<1) /* transfer start */ -#define VIA_DMA_CSR_TA (1<<2) /* transfer abort */ -#define VIA_DMA_CSR_TD (1<<3) /* transfer done */ -#define VIA_DMA_CSR_DD (1<<4) /* descriptor done */ -#define VIA_DMA_DPR_EC (1<<1) /* end of chain */ - - - -#endif diff --git a/drivers/gpu/drm/via/via_dri1.c b/drivers/gpu/drm/via/via_dri1.c new file mode 100644 index 000000000000..f659c0c0465c --- /dev/null +++ b/drivers/gpu/drm/via/via_dri1.c @@ -0,0 +1,3630 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. + * Copyright 2002 Tungsten Graphics, Inc. + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. All Rights Reserved. + * Copyright 2006 Tungsten Graphics Inc., Bismarck, ND., USA. + * Copyright 2004 Digeo, Inc., Palo Alto, CA, U.S.A. All Rights Reserved. + * Copyright 2004 The Unichrome project. All Rights Reserved. + * Copyright 2004 BEAM Ltd. + * Copyright 2005 Thomas Hellstrom. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/vmalloc.h> + +#include <drm/drm_drv.h> +#include <drm/drm_file.h> +#include <drm/drm_ioctl.h> +#include <drm/drm_legacy.h> +#include <drm/drm_mm.h> +#include <drm/drm_pciids.h> +#include <drm/drm_print.h> +#include <drm/drm_vblank.h> +#include <drm/via_drm.h> + +#include "via_3d_reg.h" + +#define DRIVER_AUTHOR "Various" + +#define DRIVER_NAME "via" +#define DRIVER_DESC "VIA Unichrome / Pro" +#define DRIVER_DATE "20070202" + +#define DRIVER_MAJOR 2 +#define DRIVER_MINOR 11 +#define DRIVER_PATCHLEVEL 1 + +typedef enum { + no_sequence = 0, + z_address, + dest_address, + tex_address +} drm_via_sequence_t; + +typedef struct { + unsigned texture; + uint32_t z_addr; + uint32_t d_addr; + uint32_t t_addr[2][10]; + uint32_t pitch[2][10]; + uint32_t height[2][10]; + uint32_t tex_level_lo[2]; + uint32_t tex_level_hi[2]; + uint32_t tex_palette_size[2]; + uint32_t tex_npot[2]; + drm_via_sequence_t unfinished; + int agp_texture; + int multitex; + struct drm_device *dev; + drm_local_map_t *map_cache; + uint32_t vertex_count; + int agp; + const uint32_t *buf_start; +} drm_via_state_t; + +#define VIA_PCI_BUF_SIZE 60000 +#define VIA_FIRE_BUF_SIZE 1024 +#define VIA_NUM_IRQS 4 + + +#define VIA_NUM_BLIT_ENGINES 2 +#define VIA_NUM_BLIT_SLOTS 8 + +struct _drm_via_descriptor; + +typedef struct _drm_via_sg_info { + struct page **pages; + unsigned long num_pages; + struct _drm_via_descriptor **desc_pages; + int num_desc_pages; + int num_desc; + enum dma_data_direction direction; + unsigned char *bounce_buffer; + dma_addr_t chain_start; + uint32_t free_on_sequence; + unsigned int descriptors_per_page; + int aborted; + enum { + dr_via_device_mapped, + dr_via_desc_pages_alloc, + dr_via_pages_locked, + dr_via_pages_alloc, + dr_via_sg_init + } state; +} drm_via_sg_info_t; + +typedef struct _drm_via_blitq { + struct drm_device *dev; + uint32_t cur_blit_handle; + uint32_t done_blit_handle; + unsigned serviced; + unsigned head; + unsigned cur; + unsigned num_free; + unsigned num_outstanding; + unsigned long end; + int aborting; + int is_active; + drm_via_sg_info_t *blits[VIA_NUM_BLIT_SLOTS]; + spinlock_t blit_lock; + wait_queue_head_t blit_queue[VIA_NUM_BLIT_SLOTS]; + wait_queue_head_t busy_queue; + struct work_struct wq; + struct timer_list poll_timer; +} drm_via_blitq_t; + +typedef struct drm_via_ring_buffer { + drm_local_map_t map; + char *virtual_start; +} drm_via_ring_buffer_t; + +typedef uint32_t maskarray_t[5]; + +typedef struct drm_via_irq { + atomic_t irq_received; + uint32_t pending_mask; + uint32_t enable_mask; + wait_queue_head_t irq_queue; +} drm_via_irq_t; + +typedef struct drm_via_private { + drm_via_sarea_t *sarea_priv; + drm_local_map_t *sarea; + drm_local_map_t *fb; + drm_local_map_t *mmio; + unsigned long agpAddr; + wait_queue_head_t decoder_queue[VIA_NR_XVMC_LOCKS]; + char *dma_ptr; + unsigned int dma_low; + unsigned int dma_high; + unsigned int dma_offset; + uint32_t dma_wrap; + volatile uint32_t *last_pause_ptr; + volatile uint32_t *hw_addr_ptr; + drm_via_ring_buffer_t ring; + ktime_t last_vblank; + int last_vblank_valid; + ktime_t nsec_per_vblank; + atomic_t vbl_received; + drm_via_state_t hc_state; + char pci_buf[VIA_PCI_BUF_SIZE]; + const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE]; + uint32_t num_fire_offsets; + int chipset; + drm_via_irq_t via_irqs[VIA_NUM_IRQS]; + unsigned num_irqs; + maskarray_t *irq_masks; + uint32_t irq_enable_mask; + uint32_t irq_pending_mask; + int *irq_map; + unsigned int idle_fault; + int vram_initialized; + struct drm_mm vram_mm; + int agp_initialized; + struct drm_mm agp_mm; + /** Mapping of userspace keys to mm objects */ + struct idr object_idr; + unsigned long vram_offset; + unsigned long agp_offset; + drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES]; + uint32_t dma_diff; +} drm_via_private_t; + +struct via_file_private { + struct list_head obj_list; +}; + +enum via_family { + VIA_OTHER = 0, /* Baseline */ + VIA_PRO_GROUP_A, /* Another video engine and DMA commands */ + VIA_DX9_0 /* Same video as pro_group_a, but 3D is unsupported */ +}; + +/* VIA MMIO register access */ +static inline u32 via_read(struct drm_via_private *dev_priv, u32 reg) +{ + return readl((void __iomem *)(dev_priv->mmio->handle + reg)); +} + +static inline void via_write(struct drm_via_private *dev_priv, u32 reg, + u32 val) +{ + writel(val, (void __iomem *)(dev_priv->mmio->handle + reg)); +} + +static inline void via_write8(struct drm_via_private *dev_priv, u32 reg, + u32 val) +{ + writeb(val, (void __iomem *)(dev_priv->mmio->handle + reg)); +} + +static inline void via_write8_mask(struct drm_via_private *dev_priv, + u32 reg, u32 mask, u32 val) +{ + u32 tmp; + + tmp = readb((void __iomem *)(dev_priv->mmio->handle + reg)); + tmp = (tmp & ~mask) | (val & mask); + writeb(tmp, (void __iomem *)(dev_priv->mmio->handle + reg)); +} + +/* + * Poll in a loop waiting for 'contidition' to be true. + * Note: A direct replacement with wait_event_interruptible_timeout() + * will not work unless driver is updated to emit wake_up() + * in relevant places that can impact the 'condition' + * + * Returns: + * ret keeps current value if 'condition' becomes true + * ret = -BUSY if timeout happens + * ret = -EINTR if a signal interrupted the waiting period + */ +#define VIA_WAIT_ON( ret, queue, timeout, condition ) \ +do { \ + DECLARE_WAITQUEUE(entry, current); \ + unsigned long end = jiffies + (timeout); \ + add_wait_queue(&(queue), &entry); \ + \ + for (;;) { \ + __set_current_state(TASK_INTERRUPTIBLE); \ + if (condition) \ + break; \ + if (time_after_eq(jiffies, end)) { \ + ret = -EBUSY; \ + break; \ + } \ + schedule_timeout((HZ/100 > 1) ? HZ/100 : 1); \ + if (signal_pending(current)) { \ + ret = -EINTR; \ + break; \ + } \ + } \ + __set_current_state(TASK_RUNNING); \ + remove_wait_queue(&(queue), &entry); \ +} while (0) + +int via_do_cleanup_map(struct drm_device *dev); + +int via_dma_cleanup(struct drm_device *dev); +int via_driver_dma_quiescent(struct drm_device *dev); + +#define CMDBUF_ALIGNMENT_SIZE (0x100) +#define CMDBUF_ALIGNMENT_MASK (0x0ff) + +/* defines for VIA 3D registers */ +#define VIA_REG_STATUS 0x400 +#define VIA_REG_TRANSET 0x43C +#define VIA_REG_TRANSPACE 0x440 + +/* VIA_REG_STATUS(0x400): Engine Status */ +#define VIA_CMD_RGTR_BUSY 0x00000080 /* Command Regulator is busy */ +#define VIA_2D_ENG_BUSY 0x00000001 /* 2D Engine is busy */ +#define VIA_3D_ENG_BUSY 0x00000002 /* 3D Engine is busy */ +#define VIA_VR_QUEUE_BUSY 0x00020000 /* Virtual Queue is busy */ + +#define SetReg2DAGP(nReg, nData) { \ + *((uint32_t *)(vb)) = ((nReg) >> 2) | HALCYON_HEADER1; \ + *((uint32_t *)(vb) + 1) = (nData); \ + vb = ((uint32_t *)vb) + 2; \ + dev_priv->dma_low += 8; \ +} + +#define via_flush_write_combine() mb() + +#define VIA_OUT_RING_QW(w1, w2) do { \ + *vb++ = (w1); \ + *vb++ = (w2); \ + dev_priv->dma_low += 8; \ +} while (0) + +#define VIA_MM_ALIGN_SHIFT 4 +#define VIA_MM_ALIGN_MASK ((1 << VIA_MM_ALIGN_SHIFT) - 1) + +struct via_memblock { + struct drm_mm_node mm_node; + struct list_head owner_list; +}; + +#define VIA_REG_INTERRUPT 0x200 + +/* VIA_REG_INTERRUPT */ +#define VIA_IRQ_GLOBAL (1 << 31) +#define VIA_IRQ_VBLANK_ENABLE (1 << 19) +#define VIA_IRQ_VBLANK_PENDING (1 << 3) +#define VIA_IRQ_HQV0_ENABLE (1 << 11) +#define VIA_IRQ_HQV1_ENABLE (1 << 25) +#define VIA_IRQ_HQV0_PENDING (1 << 9) +#define VIA_IRQ_HQV1_PENDING (1 << 10) +#define VIA_IRQ_DMA0_DD_ENABLE (1 << 20) +#define VIA_IRQ_DMA0_TD_ENABLE (1 << 21) +#define VIA_IRQ_DMA1_DD_ENABLE (1 << 22) +#define VIA_IRQ_DMA1_TD_ENABLE (1 << 23) +#define VIA_IRQ_DMA0_DD_PENDING (1 << 4) +#define VIA_IRQ_DMA0_TD_PENDING (1 << 5) +#define VIA_IRQ_DMA1_DD_PENDING (1 << 6) +#define VIA_IRQ_DMA1_TD_PENDING (1 << 7) + +/* + * PCI DMA Registers + * Channels 2 & 3 don't seem to be implemented in hardware. + */ + +#define VIA_PCI_DMA_MAR0 0xE40 /* Memory Address Register of Channel 0 */ +#define VIA_PCI_DMA_DAR0 0xE44 /* Device Address Register of Channel 0 */ +#define VIA_PCI_DMA_BCR0 0xE48 /* Byte Count Register of Channel 0 */ +#define VIA_PCI_DMA_DPR0 0xE4C /* Descriptor Pointer Register of Channel 0 */ + +#define VIA_PCI_DMA_MAR1 0xE50 /* Memory Address Register of Channel 1 */ +#define VIA_PCI_DMA_DAR1 0xE54 /* Device Address Register of Channel 1 */ +#define VIA_PCI_DMA_BCR1 0xE58 /* Byte Count Register of Channel 1 */ +#define VIA_PCI_DMA_DPR1 0xE5C /* Descriptor Pointer Register of Channel 1 */ + +#define VIA_PCI_DMA_MAR2 0xE60 /* Memory Address Register of Channel 2 */ +#define VIA_PCI_DMA_DAR2 0xE64 /* Device Address Register of Channel 2 */ +#define VIA_PCI_DMA_BCR2 0xE68 /* Byte Count Register of Channel 2 */ +#define VIA_PCI_DMA_DPR2 0xE6C /* Descriptor Pointer Register of Channel 2 */ + +#define VIA_PCI_DMA_MAR3 0xE70 /* Memory Address Register of Channel 3 */ +#define VIA_PCI_DMA_DAR3 0xE74 /* Device Address Register of Channel 3 */ +#define VIA_PCI_DMA_BCR3 0xE78 /* Byte Count Register of Channel 3 */ +#define VIA_PCI_DMA_DPR3 0xE7C /* Descriptor Pointer Register of Channel 3 */ + +#define VIA_PCI_DMA_MR0 0xE80 /* Mode Register of Channel 0 */ +#define VIA_PCI_DMA_MR1 0xE84 /* Mode Register of Channel 1 */ +#define VIA_PCI_DMA_MR2 0xE88 /* Mode Register of Channel 2 */ +#define VIA_PCI_DMA_MR3 0xE8C /* Mode Register of Channel 3 */ + +#define VIA_PCI_DMA_CSR0 0xE90 /* Command/Status Register of Channel 0 */ +#define VIA_PCI_DMA_CSR1 0xE94 /* Command/Status Register of Channel 1 */ +#define VIA_PCI_DMA_CSR2 0xE98 /* Command/Status Register of Channel 2 */ +#define VIA_PCI_DMA_CSR3 0xE9C /* Command/Status Register of Channel 3 */ + +#define VIA_PCI_DMA_PTR 0xEA0 /* Priority Type Register */ + +/* Define for DMA engine */ +/* DPR */ +#define VIA_DMA_DPR_EC (1<<1) /* end of chain */ +#define VIA_DMA_DPR_DDIE (1<<2) /* descriptor done interrupt enable */ +#define VIA_DMA_DPR_DT (1<<3) /* direction of transfer (RO) */ + +/* MR */ +#define VIA_DMA_MR_CM (1<<0) /* chaining mode */ +#define VIA_DMA_MR_TDIE (1<<1) /* transfer done interrupt enable */ +#define VIA_DMA_MR_HENDMACMD (1<<7) /* ? */ + +/* CSR */ +#define VIA_DMA_CSR_DE (1<<0) /* DMA enable */ +#define VIA_DMA_CSR_TS (1<<1) /* transfer start */ +#define VIA_DMA_CSR_TA (1<<2) /* transfer abort */ +#define VIA_DMA_CSR_TD (1<<3) /* transfer done */ +#define VIA_DMA_CSR_DD (1<<4) /* descriptor done */ +#define VIA_DMA_DPR_EC (1<<1) /* end of chain */ + +/* + * Device-specific IRQs go here. This type might need to be extended with + * the register if there are multiple IRQ control registers. + * Currently we activate the HQV interrupts of Unichrome Pro group A. + */ + +static maskarray_t via_pro_group_a_irqs[] = { + {VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010, + 0x00000000 }, + {VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010, + 0x00000000 }, + {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0, + VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, + {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1, + VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, +}; +static int via_num_pro_group_a = ARRAY_SIZE(via_pro_group_a_irqs); +static int via_irqmap_pro_group_a[] = {0, 1, -1, 2, -1, 3}; + +static maskarray_t via_unichrome_irqs[] = { + {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0, + VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, + {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1, + VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008} +}; +static int via_num_unichrome = ARRAY_SIZE(via_unichrome_irqs); +static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1}; + + +/* + * Unmaps the DMA mappings. + * FIXME: Is this a NoOp on x86? Also + * FIXME: What happens if this one is called and a pending blit has previously done + * the same DMA mappings? + */ +#define VIA_PGDN(x) (((unsigned long)(x)) & PAGE_MASK) +#define VIA_PGOFF(x) (((unsigned long)(x)) & ~PAGE_MASK) +#define VIA_PFN(x) ((unsigned long)(x) >> PAGE_SHIFT) + +typedef struct _drm_via_descriptor { + uint32_t mem_addr; + uint32_t dev_addr; + uint32_t size; + uint32_t next; +} drm_via_descriptor_t; + +typedef enum { + state_command, + state_header2, + state_header1, + state_vheader5, + state_vheader6, + state_error +} verifier_state_t; + +typedef enum { + no_check = 0, + check_for_header2, + check_for_header1, + check_for_header2_err, + check_for_header1_err, + check_for_fire, + check_z_buffer_addr0, + check_z_buffer_addr1, + check_z_buffer_addr_mode, + check_destination_addr0, + check_destination_addr1, + check_destination_addr_mode, + check_for_dummy, + check_for_dd, + check_texture_addr0, + check_texture_addr1, + check_texture_addr2, + check_texture_addr3, + check_texture_addr4, + check_texture_addr5, + check_texture_addr6, + check_texture_addr7, + check_texture_addr8, + check_texture_addr_mode, + check_for_vertex_count, + check_number_texunits, + forbidden_command +} hazard_t; + +/* + * Associates each hazard above with a possible multi-command + * sequence. For example an address that is split over multiple + * commands and that needs to be checked at the first command + * that does not include any part of the address. + */ + +static drm_via_sequence_t seqs[] = { + no_sequence, + no_sequence, + no_sequence, + no_sequence, + no_sequence, + no_sequence, + z_address, + z_address, + z_address, + dest_address, + dest_address, + dest_address, + no_sequence, + no_sequence, + tex_address, + tex_address, + tex_address, + tex_address, + tex_address, + tex_address, + tex_address, + tex_address, + tex_address, + tex_address, + no_sequence +}; + +typedef struct { + unsigned int code; + hazard_t hz; +} hz_init_t; + +static hz_init_t init_table1[] = { + {0xf2, check_for_header2_err}, + {0xf0, check_for_header1_err}, + {0xee, check_for_fire}, + {0xcc, check_for_dummy}, + {0xdd, check_for_dd}, + {0x00, no_check}, + {0x10, check_z_buffer_addr0}, + {0x11, check_z_buffer_addr1}, + {0x12, check_z_buffer_addr_mode}, + {0x13, no_check}, + {0x14, no_check}, + {0x15, no_check}, + {0x23, no_check}, + {0x24, no_check}, + {0x33, no_check}, + {0x34, no_check}, + {0x35, no_check}, + {0x36, no_check}, + {0x37, no_check}, + {0x38, no_check}, + {0x39, no_check}, + {0x3A, no_check}, + {0x3B, no_check}, + {0x3C, no_check}, + {0x3D, no_check}, + {0x3E, no_check}, + {0x40, check_destination_addr0}, + {0x41, check_destination_addr1}, + {0x42, check_destination_addr_mode}, + {0x43, no_check}, + {0x44, no_check}, + {0x50, no_check}, + {0x51, no_check}, + {0x52, no_check}, + {0x53, no_check}, + {0x54, no_check}, + {0x55, no_check}, + {0x56, no_check}, + {0x57, no_check}, + {0x58, no_check}, + {0x70, no_check}, + {0x71, no_check}, + {0x78, no_check}, + {0x79, no_check}, + {0x7A, no_check}, + {0x7B, no_check}, + {0x7C, no_check}, + {0x7D, check_for_vertex_count} +}; + +static hz_init_t init_table2[] = { + {0xf2, check_for_header2_err}, + {0xf0, check_for_header1_err}, + {0xee, check_for_fire}, + {0xcc, check_for_dummy}, + {0x00, check_texture_addr0}, + {0x01, check_texture_addr0}, + {0x02, check_texture_addr0}, + {0x03, check_texture_addr0}, + {0x04, check_texture_addr0}, + {0x05, check_texture_addr0}, + {0x06, check_texture_addr0}, + {0x07, check_texture_addr0}, + {0x08, check_texture_addr0}, + {0x09, check_texture_addr0}, + {0x20, check_texture_addr1}, + {0x21, check_texture_addr1}, + {0x22, check_texture_addr1}, + {0x23, check_texture_addr4}, + {0x2B, check_texture_addr3}, + {0x2C, check_texture_addr3}, + {0x2D, check_texture_addr3}, + {0x2E, check_texture_addr3}, + {0x2F, check_texture_addr3}, + {0x30, check_texture_addr3}, + {0x31, check_texture_addr3}, + {0x32, check_texture_addr3}, + {0x33, check_texture_addr3}, + {0x34, check_texture_addr3}, + {0x4B, check_texture_addr5}, + {0x4C, check_texture_addr6}, + {0x51, check_texture_addr7}, + {0x52, check_texture_addr8}, + {0x77, check_texture_addr2}, + {0x78, no_check}, + {0x79, no_check}, + {0x7A, no_check}, + {0x7B, check_texture_addr_mode}, + {0x7C, no_check}, + {0x7D, no_check}, + {0x7E, no_check}, + {0x7F, no_check}, + {0x80, no_check}, + {0x81, no_check}, + {0x82, no_check}, + {0x83, no_check}, + {0x85, no_check}, + {0x86, no_check}, + {0x87, no_check}, + {0x88, no_check}, + {0x89, no_check}, + {0x8A, no_check}, + {0x90, no_check}, + {0x91, no_check}, + {0x92, no_check}, + {0x93, no_check} +}; + +static hz_init_t init_table3[] = { + {0xf2, check_for_header2_err}, + {0xf0, check_for_header1_err}, + {0xcc, check_for_dummy}, + {0x00, check_number_texunits} +}; + +static hazard_t table1[256]; +static hazard_t table2[256]; +static hazard_t table3[256]; + +static __inline__ int +eat_words(const uint32_t **buf, const uint32_t *buf_end, unsigned num_words) +{ + if ((buf_end - *buf) >= num_words) { + *buf += num_words; + return 0; + } + DRM_ERROR("Illegal termination of DMA command buffer\n"); + return 1; +} + +/* + * Partially stolen from drm_memory.h + */ + +static __inline__ drm_local_map_t *via_drm_lookup_agp_map(drm_via_state_t *seq, + unsigned long offset, + unsigned long size, + struct drm_device *dev) +{ + struct drm_map_list *r_list; + drm_local_map_t *map = seq->map_cache; + + if (map && map->offset <= offset + && (offset + size) <= (map->offset + map->size)) { + return map; + } + + list_for_each_entry(r_list, &dev->maplist, head) { + map = r_list->map; + if (!map) + continue; + if (map->offset <= offset + && (offset + size) <= (map->offset + map->size) + && !(map->flags & _DRM_RESTRICTED) + && (map->type == _DRM_AGP)) { + seq->map_cache = map; + return map; + } + } + return NULL; +} + +/* + * Require that all AGP texture levels reside in the same AGP map which should + * be mappable by the client. This is not a big restriction. + * FIXME: To actually enforce this security policy strictly, drm_rmmap + * would have to wait for dma quiescent before removing an AGP map. + * The via_drm_lookup_agp_map call in reality seems to take + * very little CPU time. + */ + +static __inline__ int finish_current_sequence(drm_via_state_t * cur_seq) +{ + switch (cur_seq->unfinished) { + case z_address: + DRM_DEBUG("Z Buffer start address is 0x%x\n", cur_seq->z_addr); + break; + case dest_address: + DRM_DEBUG("Destination start address is 0x%x\n", + cur_seq->d_addr); + break; + case tex_address: + if (cur_seq->agp_texture) { + unsigned start = + cur_seq->tex_level_lo[cur_seq->texture]; + unsigned end = cur_seq->tex_level_hi[cur_seq->texture]; + unsigned long lo = ~0, hi = 0, tmp; + uint32_t *addr, *pitch, *height, tex; + unsigned i; + int npot; + + if (end > 9) + end = 9; + if (start > 9) + start = 9; + + addr = + &(cur_seq->t_addr[tex = cur_seq->texture][start]); + pitch = &(cur_seq->pitch[tex][start]); + height = &(cur_seq->height[tex][start]); + npot = cur_seq->tex_npot[tex]; + for (i = start; i <= end; ++i) { + tmp = *addr++; + if (tmp < lo) + lo = tmp; + if (i == 0 && npot) + tmp += (*height++ * *pitch++); + else + tmp += (*height++ << *pitch++); + if (tmp > hi) + hi = tmp; + } + + if (!via_drm_lookup_agp_map + (cur_seq, lo, hi - lo, cur_seq->dev)) { + DRM_ERROR + ("AGP texture is not in allowed map\n"); + return 2; + } + } + break; + default: + break; + } + cur_seq->unfinished = no_sequence; + return 0; +} + +static __inline__ int +investigate_hazard(uint32_t cmd, hazard_t hz, drm_via_state_t *cur_seq) +{ + register uint32_t tmp, *tmp_addr; + + if (cur_seq->unfinished && (cur_seq->unfinished != seqs[hz])) { + int ret; + if ((ret = finish_current_sequence(cur_seq))) + return ret; + } + + switch (hz) { + case check_for_header2: + if (cmd == HALCYON_HEADER2) + return 1; + return 0; + case check_for_header1: + if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) + return 1; + return 0; + case check_for_header2_err: + if (cmd == HALCYON_HEADER2) + return 1; + DRM_ERROR("Illegal DMA HALCYON_HEADER2 command\n"); + break; + case check_for_header1_err: + if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) + return 1; + DRM_ERROR("Illegal DMA HALCYON_HEADER1 command\n"); + break; + case check_for_fire: + if ((cmd & HALCYON_FIREMASK) == HALCYON_FIRECMD) + return 1; + DRM_ERROR("Illegal DMA HALCYON_FIRECMD command\n"); + break; + case check_for_dummy: + if (HC_DUMMY == cmd) + return 0; + DRM_ERROR("Illegal DMA HC_DUMMY command\n"); + break; + case check_for_dd: + if (0xdddddddd == cmd) + return 0; + DRM_ERROR("Illegal DMA 0xdddddddd command\n"); + break; + case check_z_buffer_addr0: + cur_seq->unfinished = z_address; + cur_seq->z_addr = (cur_seq->z_addr & 0xFF000000) | + (cmd & 0x00FFFFFF); + return 0; + case check_z_buffer_addr1: + cur_seq->unfinished = z_address; + cur_seq->z_addr = (cur_seq->z_addr & 0x00FFFFFF) | + ((cmd & 0xFF) << 24); + return 0; + case check_z_buffer_addr_mode: + cur_seq->unfinished = z_address; + if ((cmd & 0x0000C000) == 0) + return 0; + DRM_ERROR("Attempt to place Z buffer in system memory\n"); + return 2; + case check_destination_addr0: + cur_seq->unfinished = dest_address; + cur_seq->d_addr = (cur_seq->d_addr & 0xFF000000) | + (cmd & 0x00FFFFFF); + return 0; + case check_destination_addr1: + cur_seq->unfinished = dest_address; + cur_seq->d_addr = (cur_seq->d_addr & 0x00FFFFFF) | + ((cmd & 0xFF) << 24); + return 0; + case check_destination_addr_mode: + cur_seq->unfinished = dest_address; + if ((cmd & 0x0000C000) == 0) + return 0; + DRM_ERROR + ("Attempt to place 3D drawing buffer in system memory\n"); + return 2; + case check_texture_addr0: + cur_seq->unfinished = tex_address; + tmp = (cmd >> 24); + tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp]; + *tmp_addr = (*tmp_addr & 0xFF000000) | (cmd & 0x00FFFFFF); + return 0; + case check_texture_addr1: + cur_seq->unfinished = tex_address; + tmp = ((cmd >> 24) - 0x20); + tmp += tmp << 1; + tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp]; + *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24); + tmp_addr++; + *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF00) << 16); + tmp_addr++; + *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF0000) << 8); + return 0; + case check_texture_addr2: + cur_seq->unfinished = tex_address; + cur_seq->tex_level_lo[tmp = cur_seq->texture] = cmd & 0x3F; + cur_seq->tex_level_hi[tmp] = (cmd & 0xFC0) >> 6; + return 0; + case check_texture_addr3: + cur_seq->unfinished = tex_address; + tmp = ((cmd >> 24) - HC_SubA_HTXnL0Pit); + if (tmp == 0 && + (cmd & HC_HTXnEnPit_MASK)) { + cur_seq->pitch[cur_seq->texture][tmp] = + (cmd & HC_HTXnLnPit_MASK); + cur_seq->tex_npot[cur_seq->texture] = 1; + } else { + cur_seq->pitch[cur_seq->texture][tmp] = + (cmd & HC_HTXnLnPitE_MASK) >> HC_HTXnLnPitE_SHIFT; + cur_seq->tex_npot[cur_seq->texture] = 0; + if (cmd & 0x000FFFFF) { + DRM_ERROR + ("Unimplemented texture level 0 pitch mode.\n"); + return 2; + } + } + return 0; + case check_texture_addr4: + cur_seq->unfinished = tex_address; + tmp_addr = &cur_seq->t_addr[cur_seq->texture][9]; + *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24); + return 0; + case check_texture_addr5: + case check_texture_addr6: + cur_seq->unfinished = tex_address; + /* + * Texture width. We don't care since we have the pitch. + */ + return 0; + case check_texture_addr7: + cur_seq->unfinished = tex_address; + tmp_addr = &(cur_seq->height[cur_seq->texture][0]); + tmp_addr[5] = 1 << ((cmd & 0x00F00000) >> 20); + tmp_addr[4] = 1 << ((cmd & 0x000F0000) >> 16); + tmp_addr[3] = 1 << ((cmd & 0x0000F000) >> 12); + tmp_addr[2] = 1 << ((cmd & 0x00000F00) >> 8); + tmp_addr[1] = 1 << ((cmd & 0x000000F0) >> 4); + tmp_addr[0] = 1 << (cmd & 0x0000000F); + return 0; + case check_texture_addr8: + cur_seq->unfinished = tex_address; + tmp_addr = &(cur_seq->height[cur_seq->texture][0]); + tmp_addr[9] = 1 << ((cmd & 0x0000F000) >> 12); + tmp_addr[8] = 1 << ((cmd & 0x00000F00) >> 8); + tmp_addr[7] = 1 << ((cmd & 0x000000F0) >> 4); + tmp_addr[6] = 1 << (cmd & 0x0000000F); + return 0; + case check_texture_addr_mode: + cur_seq->unfinished = tex_address; + if (2 == (tmp = cmd & 0x00000003)) { + DRM_ERROR + ("Attempt to fetch texture from system memory.\n"); + return 2; + } + cur_seq->agp_texture = (tmp == 3); + cur_seq->tex_palette_size[cur_seq->texture] = + (cmd >> 16) & 0x000000007; + return 0; + case check_for_vertex_count: + cur_seq->vertex_count = cmd & 0x0000FFFF; + return 0; + case check_number_texunits: + cur_seq->multitex = (cmd >> 3) & 1; + return 0; + default: + DRM_ERROR("Illegal DMA data: 0x%x\n", cmd); + return 2; + } + return 2; +} + +static __inline__ int +via_check_prim_list(uint32_t const **buffer, const uint32_t * buf_end, + drm_via_state_t *cur_seq) +{ + drm_via_private_t *dev_priv = + (drm_via_private_t *) cur_seq->dev->dev_private; + uint32_t a_fire, bcmd, dw_count; + int ret = 0; + int have_fire; + const uint32_t *buf = *buffer; + + while (buf < buf_end) { + have_fire = 0; + if ((buf_end - buf) < 2) { + DRM_ERROR + ("Unexpected termination of primitive list.\n"); + ret = 1; + break; + } + if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdB) + break; + bcmd = *buf++; + if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdA) { + DRM_ERROR("Expected Vertex List A command, got 0x%x\n", + *buf); + ret = 1; + break; + } + a_fire = + *buf++ | HC_HPLEND_MASK | HC_HPMValidN_MASK | + HC_HE3Fire_MASK; + + /* + * How many dwords per vertex ? + */ + + if (cur_seq->agp && ((bcmd & (0xF << 11)) == 0)) { + DRM_ERROR("Illegal B command vertex data for AGP.\n"); + ret = 1; + break; + } + + dw_count = 0; + if (bcmd & (1 << 7)) + dw_count += (cur_seq->multitex) ? 2 : 1; + if (bcmd & (1 << 8)) + dw_count += (cur_seq->multitex) ? 2 : 1; + if (bcmd & (1 << 9)) + dw_count++; + if (bcmd & (1 << 10)) + dw_count++; + if (bcmd & (1 << 11)) + dw_count++; + if (bcmd & (1 << 12)) + dw_count++; + if (bcmd & (1 << 13)) + dw_count++; + if (bcmd & (1 << 14)) + dw_count++; + + while (buf < buf_end) { + if (*buf == a_fire) { + if (dev_priv->num_fire_offsets >= + VIA_FIRE_BUF_SIZE) { + DRM_ERROR("Fire offset buffer full.\n"); + ret = 1; + break; + } + dev_priv->fire_offsets[dev_priv-> + num_fire_offsets++] = + buf; + have_fire = 1; + buf++; + if (buf < buf_end && *buf == a_fire) + buf++; + break; + } + if ((*buf == HALCYON_HEADER2) || + ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD)) { + DRM_ERROR("Missing Vertex Fire command, " + "Stray Vertex Fire command or verifier " + "lost sync.\n"); + ret = 1; + break; + } + if ((ret = eat_words(&buf, buf_end, dw_count))) + break; + } + if (buf >= buf_end && !have_fire) { + DRM_ERROR("Missing Vertex Fire command or verifier " + "lost sync.\n"); + ret = 1; + break; + } + if (cur_seq->agp && ((buf - cur_seq->buf_start) & 0x01)) { + DRM_ERROR("AGP Primitive list end misaligned.\n"); + ret = 1; + break; + } + } + *buffer = buf; + return ret; +} + +static __inline__ verifier_state_t +via_check_header2(uint32_t const **buffer, const uint32_t *buf_end, + drm_via_state_t *hc_state) +{ + uint32_t cmd; + int hz_mode; + hazard_t hz; + const uint32_t *buf = *buffer; + const hazard_t *hz_table; + + if ((buf_end - buf) < 2) { + DRM_ERROR + ("Illegal termination of DMA HALCYON_HEADER2 sequence.\n"); + return state_error; + } + buf++; + cmd = (*buf++ & 0xFFFF0000) >> 16; + + switch (cmd) { + case HC_ParaType_CmdVdata: + if (via_check_prim_list(&buf, buf_end, hc_state)) + return state_error; + *buffer = buf; + return state_command; + case HC_ParaType_NotTex: + hz_table = table1; + break; + case HC_ParaType_Tex: + hc_state->texture = 0; + hz_table = table2; + break; + case (HC_ParaType_Tex | (HC_SubType_Tex1 << 8)): + hc_state->texture = 1; + hz_table = table2; + break; + case (HC_ParaType_Tex | (HC_SubType_TexGeneral << 8)): + hz_table = table3; + break; + case HC_ParaType_Auto: + if (eat_words(&buf, buf_end, 2)) + return state_error; + *buffer = buf; + return state_command; + case (HC_ParaType_Palette | (HC_SubType_Stipple << 8)): + if (eat_words(&buf, buf_end, 32)) + return state_error; + *buffer = buf; + return state_command; + case (HC_ParaType_Palette | (HC_SubType_TexPalette0 << 8)): + case (HC_ParaType_Palette | (HC_SubType_TexPalette1 << 8)): + DRM_ERROR("Texture palettes are rejected because of " + "lack of info how to determine their size.\n"); + return state_error; + case (HC_ParaType_Palette | (HC_SubType_FogTable << 8)): + DRM_ERROR("Fog factor palettes are rejected because of " + "lack of info how to determine their size.\n"); + return state_error; + default: + + /* + * There are some unimplemented HC_ParaTypes here, that + * need to be implemented if the Mesa driver is extended. + */ + + DRM_ERROR("Invalid or unimplemented HALCYON_HEADER2 " + "DMA subcommand: 0x%x. Previous dword: 0x%x\n", + cmd, *(buf - 2)); + *buffer = buf; + return state_error; + } + + while (buf < buf_end) { + cmd = *buf++; + if ((hz = hz_table[cmd >> 24])) { + if ((hz_mode = investigate_hazard(cmd, hz, hc_state))) { + if (hz_mode == 1) { + buf--; + break; + } + return state_error; + } + } else if (hc_state->unfinished && + finish_current_sequence(hc_state)) { + return state_error; + } + } + if (hc_state->unfinished && finish_current_sequence(hc_state)) + return state_error; + *buffer = buf; + return state_command; +} + +static __inline__ verifier_state_t +via_parse_header2(drm_via_private_t *dev_priv, uint32_t const **buffer, + const uint32_t *buf_end, int *fire_count) +{ + uint32_t cmd; + const uint32_t *buf = *buffer; + const uint32_t *next_fire; + int burst = 0; + + next_fire = dev_priv->fire_offsets[*fire_count]; + buf++; + cmd = (*buf & 0xFFFF0000) >> 16; + via_write(dev_priv, HC_REG_TRANS_SET + HC_REG_BASE, *buf++); + switch (cmd) { + case HC_ParaType_CmdVdata: + while ((buf < buf_end) && + (*fire_count < dev_priv->num_fire_offsets) && + (*buf & HC_ACMD_MASK) == HC_ACMD_HCmdB) { + while (buf <= next_fire) { + via_write(dev_priv, HC_REG_TRANS_SPACE + HC_REG_BASE + + (burst & 63), *buf++); + burst += 4; + } + if ((buf < buf_end) + && ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD)) + buf++; + + if (++(*fire_count) < dev_priv->num_fire_offsets) + next_fire = dev_priv->fire_offsets[*fire_count]; + } + break; + default: + while (buf < buf_end) { + + if (*buf == HC_HEADER2 || + (*buf & HALCYON_HEADER1MASK) == HALCYON_HEADER1 || + (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5 || + (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6) + break; + + via_write(dev_priv, HC_REG_TRANS_SPACE + HC_REG_BASE + + (burst & 63), *buf++); + burst += 4; + } + } + *buffer = buf; + return state_command; +} + +static __inline__ int verify_mmio_address(uint32_t address) +{ + if ((address > 0x3FF) && (address < 0xC00)) { + DRM_ERROR("Invalid VIDEO DMA command. " + "Attempt to access 3D- or command burst area.\n"); + return 1; + } else if ((address > 0xCFF) && (address < 0x1300)) { + DRM_ERROR("Invalid VIDEO DMA command. " + "Attempt to access PCI DMA area.\n"); + return 1; + } else if (address > 0x13FF) { + DRM_ERROR("Invalid VIDEO DMA command. " + "Attempt to access VGA registers.\n"); + return 1; + } + return 0; +} + +static __inline__ int +verify_video_tail(uint32_t const **buffer, const uint32_t * buf_end, + uint32_t dwords) +{ + const uint32_t *buf = *buffer; + + if (buf_end - buf < dwords) { + DRM_ERROR("Illegal termination of video command.\n"); + return 1; + } + while (dwords--) { + if (*buf++) { + DRM_ERROR("Illegal video command tail.\n"); + return 1; + } + } + *buffer = buf; + return 0; +} + +static __inline__ verifier_state_t +via_check_header1(uint32_t const **buffer, const uint32_t * buf_end) +{ + uint32_t cmd; + const uint32_t *buf = *buffer; + verifier_state_t ret = state_command; + + while (buf < buf_end) { + cmd = *buf; + if ((cmd > ((0x3FF >> 2) | HALCYON_HEADER1)) && + (cmd < ((0xC00 >> 2) | HALCYON_HEADER1))) { + if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) + break; + DRM_ERROR("Invalid HALCYON_HEADER1 command. " + "Attempt to access 3D- or command burst area.\n"); + ret = state_error; + break; + } else if (cmd > ((0xCFF >> 2) | HALCYON_HEADER1)) { + if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) + break; + DRM_ERROR("Invalid HALCYON_HEADER1 command. " + "Attempt to access VGA registers.\n"); + ret = state_error; + break; + } else { + buf += 2; + } + } + *buffer = buf; + return ret; +} + +static __inline__ verifier_state_t +via_parse_header1(drm_via_private_t *dev_priv, uint32_t const **buffer, + const uint32_t *buf_end) +{ + register uint32_t cmd; + const uint32_t *buf = *buffer; + + while (buf < buf_end) { + cmd = *buf; + if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) + break; + via_write(dev_priv, (cmd & ~HALCYON_HEADER1MASK) << 2, *++buf); + buf++; + } + *buffer = buf; + return state_command; +} + +static __inline__ verifier_state_t +via_check_vheader5(uint32_t const **buffer, const uint32_t *buf_end) +{ + uint32_t data; + const uint32_t *buf = *buffer; + + if (buf_end - buf < 4) { + DRM_ERROR("Illegal termination of video header5 command\n"); + return state_error; + } + + data = *buf++ & ~VIA_VIDEOMASK; + if (verify_mmio_address(data)) + return state_error; + + data = *buf++; + if (*buf++ != 0x00F50000) { + DRM_ERROR("Illegal header5 header data\n"); + return state_error; + } + if (*buf++ != 0x00000000) { + DRM_ERROR("Illegal header5 header data\n"); + return state_error; + } + if (eat_words(&buf, buf_end, data)) + return state_error; + if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3))) + return state_error; + *buffer = buf; + return state_command; + +} + +static __inline__ verifier_state_t +via_parse_vheader5(drm_via_private_t *dev_priv, uint32_t const **buffer, + const uint32_t *buf_end) +{ + uint32_t addr, count, i; + const uint32_t *buf = *buffer; + + addr = *buf++ & ~VIA_VIDEOMASK; + i = count = *buf; + buf += 3; + while (i--) + via_write(dev_priv, addr, *buf++); + if (count & 3) + buf += 4 - (count & 3); + *buffer = buf; + return state_command; +} + +static __inline__ verifier_state_t +via_check_vheader6(uint32_t const **buffer, const uint32_t * buf_end) +{ + uint32_t data; + const uint32_t *buf = *buffer; + uint32_t i; + + if (buf_end - buf < 4) { + DRM_ERROR("Illegal termination of video header6 command\n"); + return state_error; + } + buf++; + data = *buf++; + if (*buf++ != 0x00F60000) { + DRM_ERROR("Illegal header6 header data\n"); + return state_error; + } + if (*buf++ != 0x00000000) { + DRM_ERROR("Illegal header6 header data\n"); + return state_error; + } + if ((buf_end - buf) < (data << 1)) { + DRM_ERROR("Illegal termination of video header6 command\n"); + return state_error; + } + for (i = 0; i < data; ++i) { + if (verify_mmio_address(*buf++)) + return state_error; + buf++; + } + data <<= 1; + if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3))) + return state_error; + *buffer = buf; + return state_command; +} + +static __inline__ verifier_state_t +via_parse_vheader6(drm_via_private_t *dev_priv, uint32_t const **buffer, + const uint32_t *buf_end) +{ + + uint32_t addr, count, i; + const uint32_t *buf = *buffer; + + i = count = *++buf; + buf += 3; + while (i--) { + addr = *buf++; + via_write(dev_priv, addr, *buf++); + } + count <<= 1; + if (count & 3) + buf += 4 - (count & 3); + *buffer = buf; + return state_command; +} + +static int +via_verify_command_stream(const uint32_t * buf, unsigned int size, + struct drm_device * dev, int agp) +{ + + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + drm_via_state_t *hc_state = &dev_priv->hc_state; + drm_via_state_t saved_state = *hc_state; + uint32_t cmd; + const uint32_t *buf_end = buf + (size >> 2); + verifier_state_t state = state_command; + int cme_video; + int supported_3d; + + cme_video = (dev_priv->chipset == VIA_PRO_GROUP_A || + dev_priv->chipset == VIA_DX9_0); + + supported_3d = dev_priv->chipset != VIA_DX9_0; + + hc_state->dev = dev; + hc_state->unfinished = no_sequence; + hc_state->map_cache = NULL; + hc_state->agp = agp; + hc_state->buf_start = buf; + dev_priv->num_fire_offsets = 0; + + while (buf < buf_end) { + + switch (state) { + case state_header2: + state = via_check_header2(&buf, buf_end, hc_state); + break; + case state_header1: + state = via_check_header1(&buf, buf_end); + break; + case state_vheader5: + state = via_check_vheader5(&buf, buf_end); + break; + case state_vheader6: + state = via_check_vheader6(&buf, buf_end); + break; + case state_command: + cmd = *buf; + if ((cmd == HALCYON_HEADER2) && supported_3d) + state = state_header2; + else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) + state = state_header1; + else if (cme_video + && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5) + state = state_vheader5; + else if (cme_video + && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6) + state = state_vheader6; + else if ((cmd == HALCYON_HEADER2) && !supported_3d) { + DRM_ERROR("Accelerated 3D is not supported on this chipset yet.\n"); + state = state_error; + } else { + DRM_ERROR + ("Invalid / Unimplemented DMA HEADER command. 0x%x\n", + cmd); + state = state_error; + } + break; + case state_error: + default: + *hc_state = saved_state; + return -EINVAL; + } + } + if (state == state_error) { + *hc_state = saved_state; + return -EINVAL; + } + return 0; +} + +static int +via_parse_command_stream(struct drm_device *dev, const uint32_t *buf, + unsigned int size) +{ + + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + uint32_t cmd; + const uint32_t *buf_end = buf + (size >> 2); + verifier_state_t state = state_command; + int fire_count = 0; + + while (buf < buf_end) { + + switch (state) { + case state_header2: + state = + via_parse_header2(dev_priv, &buf, buf_end, + &fire_count); + break; + case state_header1: + state = via_parse_header1(dev_priv, &buf, buf_end); + break; + case state_vheader5: + state = via_parse_vheader5(dev_priv, &buf, buf_end); + break; + case state_vheader6: + state = via_parse_vheader6(dev_priv, &buf, buf_end); + break; + case state_command: + cmd = *buf; + if (cmd == HALCYON_HEADER2) + state = state_header2; + else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) + state = state_header1; + else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5) + state = state_vheader5; + else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6) + state = state_vheader6; + else { + DRM_ERROR + ("Invalid / Unimplemented DMA HEADER command. 0x%x\n", + cmd); + state = state_error; + } + break; + case state_error: + default: + return -EINVAL; + } + } + if (state == state_error) + return -EINVAL; + return 0; +} + +static void +setup_hazard_table(hz_init_t init_table[], hazard_t table[], int size) +{ + int i; + + for (i = 0; i < 256; ++i) + table[i] = forbidden_command; + + for (i = 0; i < size; ++i) + table[init_table[i].code] = init_table[i].hz; +} + +static void via_init_command_verifier(void) +{ + setup_hazard_table(init_table1, table1, ARRAY_SIZE(init_table1)); + setup_hazard_table(init_table2, table2, ARRAY_SIZE(init_table2)); + setup_hazard_table(init_table3, table3, ARRAY_SIZE(init_table3)); +} +/* + * Unmap a DMA mapping. + */ +static void +via_unmap_blit_from_device(struct pci_dev *pdev, drm_via_sg_info_t *vsg) +{ + int num_desc = vsg->num_desc; + unsigned cur_descriptor_page = num_desc / vsg->descriptors_per_page; + unsigned descriptor_this_page = num_desc % vsg->descriptors_per_page; + drm_via_descriptor_t *desc_ptr = vsg->desc_pages[cur_descriptor_page] + + descriptor_this_page; + dma_addr_t next = vsg->chain_start; + + while (num_desc--) { + if (descriptor_this_page-- == 0) { + cur_descriptor_page--; + descriptor_this_page = vsg->descriptors_per_page - 1; + desc_ptr = vsg->desc_pages[cur_descriptor_page] + + descriptor_this_page; + } + dma_unmap_single(&pdev->dev, next, sizeof(*desc_ptr), DMA_TO_DEVICE); + dma_unmap_page(&pdev->dev, desc_ptr->mem_addr, desc_ptr->size, vsg->direction); + next = (dma_addr_t) desc_ptr->next; + desc_ptr--; + } +} + +/* + * If mode = 0, count how many descriptors are needed. + * If mode = 1, Map the DMA pages for the device, put together and map also the descriptors. + * Descriptors are run in reverse order by the hardware because we are not allowed to update the + * 'next' field without syncing calls when the descriptor is already mapped. + */ +static void +via_map_blit_for_device(struct pci_dev *pdev, + const drm_via_dmablit_t *xfer, + drm_via_sg_info_t *vsg, + int mode) +{ + unsigned cur_descriptor_page = 0; + unsigned num_descriptors_this_page = 0; + unsigned char *mem_addr = xfer->mem_addr; + unsigned char *cur_mem; + unsigned char *first_addr = (unsigned char *)VIA_PGDN(mem_addr); + uint32_t fb_addr = xfer->fb_addr; + uint32_t cur_fb; + unsigned long line_len; + unsigned remaining_len; + int num_desc = 0; + int cur_line; + dma_addr_t next = 0 | VIA_DMA_DPR_EC; + drm_via_descriptor_t *desc_ptr = NULL; + + if (mode == 1) + desc_ptr = vsg->desc_pages[cur_descriptor_page]; + + for (cur_line = 0; cur_line < xfer->num_lines; ++cur_line) { + + line_len = xfer->line_length; + cur_fb = fb_addr; + cur_mem = mem_addr; + + while (line_len > 0) { + + remaining_len = min(PAGE_SIZE-VIA_PGOFF(cur_mem), line_len); + line_len -= remaining_len; + + if (mode == 1) { + desc_ptr->mem_addr = + dma_map_page(&pdev->dev, + vsg->pages[VIA_PFN(cur_mem) - + VIA_PFN(first_addr)], + VIA_PGOFF(cur_mem), remaining_len, + vsg->direction); + desc_ptr->dev_addr = cur_fb; + + desc_ptr->size = remaining_len; + desc_ptr->next = (uint32_t) next; + next = dma_map_single(&pdev->dev, desc_ptr, sizeof(*desc_ptr), + DMA_TO_DEVICE); + desc_ptr++; + if (++num_descriptors_this_page >= vsg->descriptors_per_page) { + num_descriptors_this_page = 0; + desc_ptr = vsg->desc_pages[++cur_descriptor_page]; + } + } + + num_desc++; + cur_mem += remaining_len; + cur_fb += remaining_len; + } + + mem_addr += xfer->mem_stride; + fb_addr += xfer->fb_stride; + } + + if (mode == 1) { + vsg->chain_start = next; + vsg->state = dr_via_device_mapped; + } + vsg->num_desc = num_desc; +} + +/* + * Function that frees up all resources for a blit. It is usable even if the + * blit info has only been partially built as long as the status enum is consistent + * with the actual status of the used resources. + */ +static void +via_free_sg_info(struct pci_dev *pdev, drm_via_sg_info_t *vsg) +{ + int i; + + switch (vsg->state) { + case dr_via_device_mapped: + via_unmap_blit_from_device(pdev, vsg); + fallthrough; + case dr_via_desc_pages_alloc: + for (i = 0; i < vsg->num_desc_pages; ++i) { + if (vsg->desc_pages[i] != NULL) + free_page((unsigned long)vsg->desc_pages[i]); + } + kfree(vsg->desc_pages); + fallthrough; + case dr_via_pages_locked: + unpin_user_pages_dirty_lock(vsg->pages, vsg->num_pages, + (vsg->direction == DMA_FROM_DEVICE)); + fallthrough; + case dr_via_pages_alloc: + vfree(vsg->pages); + fallthrough; + default: + vsg->state = dr_via_sg_init; + } + vfree(vsg->bounce_buffer); + vsg->bounce_buffer = NULL; + vsg->free_on_sequence = 0; +} + +/* + * Fire a blit engine. + */ +static void +via_fire_dmablit(struct drm_device *dev, drm_via_sg_info_t *vsg, int engine) +{ + drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; + + via_write(dev_priv, VIA_PCI_DMA_MAR0 + engine*0x10, 0); + via_write(dev_priv, VIA_PCI_DMA_DAR0 + engine*0x10, 0); + via_write(dev_priv, VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_DD | VIA_DMA_CSR_TD | + VIA_DMA_CSR_DE); + via_write(dev_priv, VIA_PCI_DMA_MR0 + engine*0x04, VIA_DMA_MR_CM | VIA_DMA_MR_TDIE); + via_write(dev_priv, VIA_PCI_DMA_BCR0 + engine*0x10, 0); + via_write(dev_priv, VIA_PCI_DMA_DPR0 + engine*0x10, vsg->chain_start); + wmb(); + via_write(dev_priv, VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_DE | VIA_DMA_CSR_TS); + via_read(dev_priv, VIA_PCI_DMA_CSR0 + engine*0x04); +} + +/* + * Obtain a page pointer array and lock all pages into system memory. A segmentation violation will + * occur here if the calling user does not have access to the submitted address. + */ +static int +via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer) +{ + int ret; + unsigned long first_pfn = VIA_PFN(xfer->mem_addr); + vsg->num_pages = VIA_PFN(xfer->mem_addr + (xfer->num_lines * xfer->mem_stride - 1)) - + first_pfn + 1; + + vsg->pages = vzalloc(array_size(sizeof(struct page *), vsg->num_pages)); + if (NULL == vsg->pages) + return -ENOMEM; + ret = pin_user_pages_fast((unsigned long)xfer->mem_addr, + vsg->num_pages, + vsg->direction == DMA_FROM_DEVICE ? FOLL_WRITE : 0, + vsg->pages); + if (ret != vsg->num_pages) { + if (ret < 0) + return ret; + vsg->state = dr_via_pages_locked; + return -EINVAL; + } + vsg->state = dr_via_pages_locked; + DRM_DEBUG("DMA pages locked\n"); + return 0; +} + +/* + * Allocate DMA capable memory for the blit descriptor chain, and an array that keeps track of the + * pages we allocate. We don't want to use kmalloc for the descriptor chain because it may be + * quite large for some blits, and pages don't need to be contiguous. + */ +static int +via_alloc_desc_pages(drm_via_sg_info_t *vsg) +{ + int i; + + vsg->descriptors_per_page = PAGE_SIZE / sizeof(drm_via_descriptor_t); + vsg->num_desc_pages = (vsg->num_desc + vsg->descriptors_per_page - 1) / + vsg->descriptors_per_page; + + if (NULL == (vsg->desc_pages = kcalloc(vsg->num_desc_pages, sizeof(void *), GFP_KERNEL))) + return -ENOMEM; + + vsg->state = dr_via_desc_pages_alloc; + for (i = 0; i < vsg->num_desc_pages; ++i) { + if (NULL == (vsg->desc_pages[i] = + (drm_via_descriptor_t *) __get_free_page(GFP_KERNEL))) + return -ENOMEM; + } + DRM_DEBUG("Allocated %d pages for %d descriptors.\n", vsg->num_desc_pages, + vsg->num_desc); + return 0; +} + +static void +via_abort_dmablit(struct drm_device *dev, int engine) +{ + drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; + + via_write(dev_priv, VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_TA); +} + +static void +via_dmablit_engine_off(struct drm_device *dev, int engine) +{ + drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; + + via_write(dev_priv, VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_TD | VIA_DMA_CSR_DD); +} + +/* + * The dmablit part of the IRQ handler. Trying to do only reasonably fast things here. + * The rest, like unmapping and freeing memory for done blits is done in a separate workqueue + * task. Basically the task of the interrupt handler is to submit a new blit to the engine, while + * the workqueue task takes care of processing associated with the old blit. + */ +static void +via_dmablit_handler(struct drm_device *dev, int engine, int from_irq) +{ + drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; + drm_via_blitq_t *blitq = dev_priv->blit_queues + engine; + int cur; + int done_transfer; + unsigned long irqsave = 0; + uint32_t status = 0; + + DRM_DEBUG("DMA blit handler called. engine = %d, from_irq = %d, blitq = 0x%lx\n", + engine, from_irq, (unsigned long) blitq); + + if (from_irq) + spin_lock(&blitq->blit_lock); + else + spin_lock_irqsave(&blitq->blit_lock, irqsave); + + done_transfer = blitq->is_active && + ((status = via_read(dev_priv, VIA_PCI_DMA_CSR0 + engine*0x04)) & VIA_DMA_CSR_TD); + done_transfer = done_transfer || (blitq->aborting && !(status & VIA_DMA_CSR_DE)); + + cur = blitq->cur; + if (done_transfer) { + + blitq->blits[cur]->aborted = blitq->aborting; + blitq->done_blit_handle++; + wake_up(blitq->blit_queue + cur); + + cur++; + if (cur >= VIA_NUM_BLIT_SLOTS) + cur = 0; + blitq->cur = cur; + + /* + * Clear transfer done flag. + */ + + via_write(dev_priv, VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_TD); + + blitq->is_active = 0; + blitq->aborting = 0; + schedule_work(&blitq->wq); + + } else if (blitq->is_active && time_after_eq(jiffies, blitq->end)) { + + /* + * Abort transfer after one second. + */ + + via_abort_dmablit(dev, engine); + blitq->aborting = 1; + blitq->end = jiffies + HZ; + } + + if (!blitq->is_active) { + if (blitq->num_outstanding) { + via_fire_dmablit(dev, blitq->blits[cur], engine); + blitq->is_active = 1; + blitq->cur = cur; + blitq->num_outstanding--; + blitq->end = jiffies + HZ; + if (!timer_pending(&blitq->poll_timer)) + mod_timer(&blitq->poll_timer, jiffies + 1); + } else { + if (timer_pending(&blitq->poll_timer)) + del_timer(&blitq->poll_timer); + via_dmablit_engine_off(dev, engine); + } + } + + if (from_irq) + spin_unlock(&blitq->blit_lock); + else + spin_unlock_irqrestore(&blitq->blit_lock, irqsave); +} + +/* + * Check whether this blit is still active, performing necessary locking. + */ +static int +via_dmablit_active(drm_via_blitq_t *blitq, int engine, uint32_t handle, wait_queue_head_t **queue) +{ + unsigned long irqsave; + uint32_t slot; + int active; + + spin_lock_irqsave(&blitq->blit_lock, irqsave); + + /* + * Allow for handle wraparounds. + */ + + active = ((blitq->done_blit_handle - handle) > (1 << 23)) && + ((blitq->cur_blit_handle - handle) <= (1 << 23)); + + if (queue && active) { + slot = handle - blitq->done_blit_handle + blitq->cur - 1; + if (slot >= VIA_NUM_BLIT_SLOTS) + slot -= VIA_NUM_BLIT_SLOTS; + *queue = blitq->blit_queue + slot; + } + + spin_unlock_irqrestore(&blitq->blit_lock, irqsave); + + return active; +} + +/* + * Sync. Wait for at least three seconds for the blit to be performed. + */ +static int +via_dmablit_sync(struct drm_device *dev, uint32_t handle, int engine) +{ + + drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; + drm_via_blitq_t *blitq = dev_priv->blit_queues + engine; + wait_queue_head_t *queue; + int ret = 0; + + if (via_dmablit_active(blitq, engine, handle, &queue)) { + VIA_WAIT_ON(ret, *queue, 3 * HZ, + !via_dmablit_active(blitq, engine, handle, NULL)); + } + DRM_DEBUG("DMA blit sync handle 0x%x engine %d returned %d\n", + handle, engine, ret); + + return ret; +} + +/* + * A timer that regularly polls the blit engine in cases where we don't have interrupts: + * a) Broken hardware (typically those that don't have any video capture facility). + * b) Blit abort. The hardware doesn't send an interrupt when a blit is aborted. + * The timer and hardware IRQ's can and do work in parallel. If the hardware has + * irqs, it will shorten the latency somewhat. + */ +static void +via_dmablit_timer(struct timer_list *t) +{ + drm_via_blitq_t *blitq = from_timer(blitq, t, poll_timer); + struct drm_device *dev = blitq->dev; + int engine = (int) + (blitq - ((drm_via_private_t *)dev->dev_private)->blit_queues); + + DRM_DEBUG("Polling timer called for engine %d, jiffies %lu\n", engine, + (unsigned long) jiffies); + + via_dmablit_handler(dev, engine, 0); + + if (!timer_pending(&blitq->poll_timer)) { + mod_timer(&blitq->poll_timer, jiffies + 1); + + /* + * Rerun handler to delete timer if engines are off, and + * to shorten abort latency. This is a little nasty. + */ + + via_dmablit_handler(dev, engine, 0); + + } +} + +/* + * Workqueue task that frees data and mappings associated with a blit. + * Also wakes up waiting processes. Each of these tasks handles one + * blit engine only and may not be called on each interrupt. + */ +static void +via_dmablit_workqueue(struct work_struct *work) +{ + drm_via_blitq_t *blitq = container_of(work, drm_via_blitq_t, wq); + struct drm_device *dev = blitq->dev; + struct pci_dev *pdev = to_pci_dev(dev->dev); + unsigned long irqsave; + drm_via_sg_info_t *cur_sg; + int cur_released; + + + DRM_DEBUG("Workqueue task called for blit engine %ld\n", (unsigned long) + (blitq - ((drm_via_private_t *)dev->dev_private)->blit_queues)); + + spin_lock_irqsave(&blitq->blit_lock, irqsave); + + while (blitq->serviced != blitq->cur) { + + cur_released = blitq->serviced++; + + DRM_DEBUG("Releasing blit slot %d\n", cur_released); + + if (blitq->serviced >= VIA_NUM_BLIT_SLOTS) + blitq->serviced = 0; + + cur_sg = blitq->blits[cur_released]; + blitq->num_free++; + + spin_unlock_irqrestore(&blitq->blit_lock, irqsave); + + wake_up(&blitq->busy_queue); + + via_free_sg_info(pdev, cur_sg); + kfree(cur_sg); + + spin_lock_irqsave(&blitq->blit_lock, irqsave); + } + + spin_unlock_irqrestore(&blitq->blit_lock, irqsave); +} + +/* + * Init all blit engines. Currently we use two, but some hardware have 4. + */ +static void +via_init_dmablit(struct drm_device *dev) +{ + int i, j; + drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; + struct pci_dev *pdev = to_pci_dev(dev->dev); + drm_via_blitq_t *blitq; + + pci_set_master(pdev); + + for (i = 0; i < VIA_NUM_BLIT_ENGINES; ++i) { + blitq = dev_priv->blit_queues + i; + blitq->dev = dev; + blitq->cur_blit_handle = 0; + blitq->done_blit_handle = 0; + blitq->head = 0; + blitq->cur = 0; + blitq->serviced = 0; + blitq->num_free = VIA_NUM_BLIT_SLOTS - 1; + blitq->num_outstanding = 0; + blitq->is_active = 0; + blitq->aborting = 0; + spin_lock_init(&blitq->blit_lock); + for (j = 0; j < VIA_NUM_BLIT_SLOTS; ++j) + init_waitqueue_head(blitq->blit_queue + j); + init_waitqueue_head(&blitq->busy_queue); + INIT_WORK(&blitq->wq, via_dmablit_workqueue); + timer_setup(&blitq->poll_timer, via_dmablit_timer, 0); + } +} + +/* + * Build all info and do all mappings required for a blit. + */ +static int +via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer) +{ + struct pci_dev *pdev = to_pci_dev(dev->dev); + int draw = xfer->to_fb; + int ret = 0; + + vsg->direction = (draw) ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + vsg->bounce_buffer = NULL; + + vsg->state = dr_via_sg_init; + + if (xfer->num_lines <= 0 || xfer->line_length <= 0) { + DRM_ERROR("Zero size bitblt.\n"); + return -EINVAL; + } + + /* + * Below check is a driver limitation, not a hardware one. We + * don't want to lock unused pages, and don't want to incoporate the + * extra logic of avoiding them. Make sure there are no. + * (Not a big limitation anyway.) + */ + + if ((xfer->mem_stride - xfer->line_length) > 2*PAGE_SIZE) { + DRM_ERROR("Too large system memory stride. Stride: %d, " + "Length: %d\n", xfer->mem_stride, xfer->line_length); + return -EINVAL; + } + + if ((xfer->mem_stride == xfer->line_length) && + (xfer->fb_stride == xfer->line_length)) { + xfer->mem_stride *= xfer->num_lines; + xfer->line_length = xfer->mem_stride; + xfer->fb_stride = xfer->mem_stride; + xfer->num_lines = 1; + } + + /* + * Don't lock an arbitrary large number of pages, since that causes a + * DOS security hole. + */ + + if (xfer->num_lines > 2048 || (xfer->num_lines*xfer->mem_stride > (2048*2048*4))) { + DRM_ERROR("Too large PCI DMA bitblt.\n"); + return -EINVAL; + } + + /* + * we allow a negative fb stride to allow flipping of images in + * transfer. + */ + + if (xfer->mem_stride < xfer->line_length || + abs(xfer->fb_stride) < xfer->line_length) { + DRM_ERROR("Invalid frame-buffer / memory stride.\n"); + return -EINVAL; + } + + /* + * A hardware bug seems to be worked around if system memory addresses start on + * 16 byte boundaries. This seems a bit restrictive however. VIA is contacted + * about this. Meanwhile, impose the following restrictions: + */ + +#ifdef VIA_BUGFREE + if ((((unsigned long)xfer->mem_addr & 3) != ((unsigned long)xfer->fb_addr & 3)) || + ((xfer->num_lines > 1) && ((xfer->mem_stride & 3) != (xfer->fb_stride & 3)))) { + DRM_ERROR("Invalid DRM bitblt alignment.\n"); + return -EINVAL; + } +#else + if ((((unsigned long)xfer->mem_addr & 15) || + ((unsigned long)xfer->fb_addr & 3)) || + ((xfer->num_lines > 1) && + ((xfer->mem_stride & 15) || (xfer->fb_stride & 3)))) { + DRM_ERROR("Invalid DRM bitblt alignment.\n"); + return -EINVAL; + } +#endif + + if (0 != (ret = via_lock_all_dma_pages(vsg, xfer))) { + DRM_ERROR("Could not lock DMA pages.\n"); + via_free_sg_info(pdev, vsg); + return ret; + } + + via_map_blit_for_device(pdev, xfer, vsg, 0); + if (0 != (ret = via_alloc_desc_pages(vsg))) { + DRM_ERROR("Could not allocate DMA descriptor pages.\n"); + via_free_sg_info(pdev, vsg); + return ret; + } + via_map_blit_for_device(pdev, xfer, vsg, 1); + + return 0; +} + +/* + * Reserve one free slot in the blit queue. Will wait for one second for one + * to become available. Otherwise -EBUSY is returned. + */ +static int +via_dmablit_grab_slot(drm_via_blitq_t *blitq, int engine) +{ + int ret = 0; + unsigned long irqsave; + + DRM_DEBUG("Num free is %d\n", blitq->num_free); + spin_lock_irqsave(&blitq->blit_lock, irqsave); + while (blitq->num_free == 0) { + spin_unlock_irqrestore(&blitq->blit_lock, irqsave); + + VIA_WAIT_ON(ret, blitq->busy_queue, HZ, blitq->num_free > 0); + if (ret) + return (-EINTR == ret) ? -EAGAIN : ret; + + spin_lock_irqsave(&blitq->blit_lock, irqsave); + } + + blitq->num_free--; + spin_unlock_irqrestore(&blitq->blit_lock, irqsave); + + return 0; +} + +/* + * Hand back a free slot if we changed our mind. + */ +static void +via_dmablit_release_slot(drm_via_blitq_t *blitq) +{ + unsigned long irqsave; + + spin_lock_irqsave(&blitq->blit_lock, irqsave); + blitq->num_free++; + spin_unlock_irqrestore(&blitq->blit_lock, irqsave); + wake_up(&blitq->busy_queue); +} + +/* + * Grab a free slot. Build blit info and queue a blit. + */ +static int +via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer) +{ + drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; + drm_via_sg_info_t *vsg; + drm_via_blitq_t *blitq; + int ret; + int engine; + unsigned long irqsave; + + if (dev_priv == NULL) { + DRM_ERROR("Called without initialization.\n"); + return -EINVAL; + } + + engine = (xfer->to_fb) ? 0 : 1; + blitq = dev_priv->blit_queues + engine; + if (0 != (ret = via_dmablit_grab_slot(blitq, engine))) + return ret; + if (NULL == (vsg = kmalloc(sizeof(*vsg), GFP_KERNEL))) { + via_dmablit_release_slot(blitq); + return -ENOMEM; + } + if (0 != (ret = via_build_sg_info(dev, vsg, xfer))) { + via_dmablit_release_slot(blitq); + kfree(vsg); + return ret; + } + spin_lock_irqsave(&blitq->blit_lock, irqsave); + + blitq->blits[blitq->head++] = vsg; + if (blitq->head >= VIA_NUM_BLIT_SLOTS) + blitq->head = 0; + blitq->num_outstanding++; + xfer->sync.sync_handle = ++blitq->cur_blit_handle; + + spin_unlock_irqrestore(&blitq->blit_lock, irqsave); + xfer->sync.engine = engine; + + via_dmablit_handler(dev, engine, 0); + + return 0; +} + +/* + * Sync on a previously submitted blit. Note that the X server use signals extensively, and + * that there is a very big probability that this IOCTL will be interrupted by a signal. In that + * case it returns with -EAGAIN for the signal to be delivered. + * The caller should then reissue the IOCTL. This is similar to what is being done for drmGetLock(). + */ +static int +via_dma_blit_sync(struct drm_device *dev, void *data, struct drm_file *file_priv) +{ + drm_via_blitsync_t *sync = data; + int err; + + if (sync->engine >= VIA_NUM_BLIT_ENGINES) + return -EINVAL; + + err = via_dmablit_sync(dev, sync->sync_handle, sync->engine); + + if (-EINTR == err) + err = -EAGAIN; + + return err; +} + +/* + * Queue a blit and hand back a handle to be used for sync. This IOCTL may be interrupted by a signal + * while waiting for a free slot in the blit queue. In that case it returns with -EAGAIN and should + * be reissued. See the above IOCTL code. + */ +static int +via_dma_blit(struct drm_device *dev, void *data, struct drm_file *file_priv) +{ + drm_via_dmablit_t *xfer = data; + int err; + + err = via_dmablit(dev, xfer); + + return err; +} + +static u32 via_get_vblank_counter(struct drm_device *dev, unsigned int pipe) +{ + drm_via_private_t *dev_priv = dev->dev_private; + + if (pipe != 0) + return 0; + + return atomic_read(&dev_priv->vbl_received); +} + +static irqreturn_t via_driver_irq_handler(int irq, void *arg) +{ + struct drm_device *dev = (struct drm_device *) arg; + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + u32 status; + int handled = 0; + ktime_t cur_vblank; + drm_via_irq_t *cur_irq = dev_priv->via_irqs; + int i; + + status = via_read(dev_priv, VIA_REG_INTERRUPT); + if (status & VIA_IRQ_VBLANK_PENDING) { + atomic_inc(&dev_priv->vbl_received); + if (!(atomic_read(&dev_priv->vbl_received) & 0x0F)) { + cur_vblank = ktime_get(); + if (dev_priv->last_vblank_valid) { + dev_priv->nsec_per_vblank = + ktime_sub(cur_vblank, + dev_priv->last_vblank) >> 4; + } + dev_priv->last_vblank = cur_vblank; + dev_priv->last_vblank_valid = 1; + } + if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) { + DRM_DEBUG("nsec per vblank is: %llu\n", + ktime_to_ns(dev_priv->nsec_per_vblank)); + } + drm_handle_vblank(dev, 0); + handled = 1; + } + + for (i = 0; i < dev_priv->num_irqs; ++i) { + if (status & cur_irq->pending_mask) { + atomic_inc(&cur_irq->irq_received); + wake_up(&cur_irq->irq_queue); + handled = 1; + if (dev_priv->irq_map[drm_via_irq_dma0_td] == i) + via_dmablit_handler(dev, 0, 1); + else if (dev_priv->irq_map[drm_via_irq_dma1_td] == i) + via_dmablit_handler(dev, 1, 1); + } + cur_irq++; + } + + /* Acknowledge interrupts */ + via_write(dev_priv, VIA_REG_INTERRUPT, status); + + + if (handled) + return IRQ_HANDLED; + else + return IRQ_NONE; +} + +static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t *dev_priv) +{ + u32 status; + + if (dev_priv) { + /* Acknowledge interrupts */ + status = via_read(dev_priv, VIA_REG_INTERRUPT); + via_write(dev_priv, VIA_REG_INTERRUPT, status | + dev_priv->irq_pending_mask); + } +} + +static int via_enable_vblank(struct drm_device *dev, unsigned int pipe) +{ + drm_via_private_t *dev_priv = dev->dev_private; + u32 status; + + if (pipe != 0) { + DRM_ERROR("%s: bad crtc %u\n", __func__, pipe); + return -EINVAL; + } + + status = via_read(dev_priv, VIA_REG_INTERRUPT); + via_write(dev_priv, VIA_REG_INTERRUPT, status | VIA_IRQ_VBLANK_ENABLE); + + via_write8(dev_priv, 0x83d4, 0x11); + via_write8_mask(dev_priv, 0x83d5, 0x30, 0x30); + + return 0; +} + +static void via_disable_vblank(struct drm_device *dev, unsigned int pipe) +{ + drm_via_private_t *dev_priv = dev->dev_private; + u32 status; + + status = via_read(dev_priv, VIA_REG_INTERRUPT); + via_write(dev_priv, VIA_REG_INTERRUPT, status & ~VIA_IRQ_VBLANK_ENABLE); + + via_write8(dev_priv, 0x83d4, 0x11); + via_write8_mask(dev_priv, 0x83d5, 0x30, 0); + + if (pipe != 0) + DRM_ERROR("%s: bad crtc %u\n", __func__, pipe); +} + +static int +via_driver_irq_wait(struct drm_device *dev, unsigned int irq, int force_sequence, + unsigned int *sequence) +{ + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + unsigned int cur_irq_sequence; + drm_via_irq_t *cur_irq; + int ret = 0; + maskarray_t *masks; + int real_irq; + + DRM_DEBUG("\n"); + + if (!dev_priv) { + DRM_ERROR("called with no initialization\n"); + return -EINVAL; + } + + if (irq >= drm_via_irq_num) { + DRM_ERROR("Trying to wait on unknown irq %d\n", irq); + return -EINVAL; + } + + real_irq = dev_priv->irq_map[irq]; + + if (real_irq < 0) { + DRM_ERROR("Video IRQ %d not available on this hardware.\n", + irq); + return -EINVAL; + } + + masks = dev_priv->irq_masks; + cur_irq = dev_priv->via_irqs + real_irq; + + if (masks[real_irq][2] && !force_sequence) { + VIA_WAIT_ON(ret, cur_irq->irq_queue, 3 * HZ, + ((via_read(dev_priv, masks[irq][2]) & masks[irq][3]) == + masks[irq][4])); + cur_irq_sequence = atomic_read(&cur_irq->irq_received); + } else { + VIA_WAIT_ON(ret, cur_irq->irq_queue, 3 * HZ, + (((cur_irq_sequence = + atomic_read(&cur_irq->irq_received)) - + *sequence) <= (1 << 23))); + } + *sequence = cur_irq_sequence; + return ret; +} + + +/* + * drm_dma.h hooks + */ + +static void via_driver_irq_preinstall(struct drm_device *dev) +{ + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + u32 status; + drm_via_irq_t *cur_irq; + int i; + + DRM_DEBUG("dev_priv: %p\n", dev_priv); + if (dev_priv) { + cur_irq = dev_priv->via_irqs; + + dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE; + dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING; + + if (dev_priv->chipset == VIA_PRO_GROUP_A || + dev_priv->chipset == VIA_DX9_0) { + dev_priv->irq_masks = via_pro_group_a_irqs; + dev_priv->num_irqs = via_num_pro_group_a; + dev_priv->irq_map = via_irqmap_pro_group_a; + } else { + dev_priv->irq_masks = via_unichrome_irqs; + dev_priv->num_irqs = via_num_unichrome; + dev_priv->irq_map = via_irqmap_unichrome; + } + + for (i = 0; i < dev_priv->num_irqs; ++i) { + atomic_set(&cur_irq->irq_received, 0); + cur_irq->enable_mask = dev_priv->irq_masks[i][0]; + cur_irq->pending_mask = dev_priv->irq_masks[i][1]; + init_waitqueue_head(&cur_irq->irq_queue); + dev_priv->irq_enable_mask |= cur_irq->enable_mask; + dev_priv->irq_pending_mask |= cur_irq->pending_mask; + cur_irq++; + + DRM_DEBUG("Initializing IRQ %d\n", i); + } + + dev_priv->last_vblank_valid = 0; + + /* Clear VSync interrupt regs */ + status = via_read(dev_priv, VIA_REG_INTERRUPT); + via_write(dev_priv, VIA_REG_INTERRUPT, status & + ~(dev_priv->irq_enable_mask)); + + /* Clear bits if they're already high */ + viadrv_acknowledge_irqs(dev_priv); + } +} + +static int via_driver_irq_postinstall(struct drm_device *dev) +{ + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + u32 status; + + DRM_DEBUG("fun: %s\n", __func__); + if (!dev_priv) + return -EINVAL; + + status = via_read(dev_priv, VIA_REG_INTERRUPT); + via_write(dev_priv, VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL + | dev_priv->irq_enable_mask); + + /* Some magic, oh for some data sheets ! */ + via_write8(dev_priv, 0x83d4, 0x11); + via_write8_mask(dev_priv, 0x83d5, 0x30, 0x30); + + return 0; +} + +static void via_driver_irq_uninstall(struct drm_device *dev) +{ + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + u32 status; + + DRM_DEBUG("\n"); + if (dev_priv) { + + /* Some more magic, oh for some data sheets ! */ + + via_write8(dev_priv, 0x83d4, 0x11); + via_write8_mask(dev_priv, 0x83d5, 0x30, 0); + + status = via_read(dev_priv, VIA_REG_INTERRUPT); + via_write(dev_priv, VIA_REG_INTERRUPT, status & + ~(VIA_IRQ_VBLANK_ENABLE | dev_priv->irq_enable_mask)); + } +} + +static int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv) +{ + drm_via_irqwait_t *irqwait = data; + struct timespec64 now; + int ret = 0; + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + drm_via_irq_t *cur_irq = dev_priv->via_irqs; + int force_sequence; + + if (irqwait->request.irq >= dev_priv->num_irqs) { + DRM_ERROR("Trying to wait on unknown irq %d\n", + irqwait->request.irq); + return -EINVAL; + } + + cur_irq += irqwait->request.irq; + + switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) { + case VIA_IRQ_RELATIVE: + irqwait->request.sequence += + atomic_read(&cur_irq->irq_received); + irqwait->request.type &= ~_DRM_VBLANK_RELATIVE; + break; + case VIA_IRQ_ABSOLUTE: + break; + default: + return -EINVAL; + } + + if (irqwait->request.type & VIA_IRQ_SIGNAL) { + DRM_ERROR("Signals on Via IRQs not implemented yet.\n"); + return -EINVAL; + } + + force_sequence = (irqwait->request.type & VIA_IRQ_FORCE_SEQUENCE); + + ret = via_driver_irq_wait(dev, irqwait->request.irq, force_sequence, + &irqwait->request.sequence); + ktime_get_ts64(&now); + irqwait->reply.tval_sec = now.tv_sec; + irqwait->reply.tval_usec = now.tv_nsec / NSEC_PER_USEC; + + return ret; +} + +static void via_init_futex(drm_via_private_t *dev_priv) +{ + unsigned int i; + + DRM_DEBUG("\n"); + + for (i = 0; i < VIA_NR_XVMC_LOCKS; ++i) { + init_waitqueue_head(&(dev_priv->decoder_queue[i])); + XVMCLOCKPTR(dev_priv->sarea_priv, i)->lock = 0; + } +} + +static void via_cleanup_futex(drm_via_private_t *dev_priv) +{ +} + +static void via_release_futex(drm_via_private_t *dev_priv, int context) +{ + unsigned int i; + volatile int *lock; + + if (!dev_priv->sarea_priv) + return; + + for (i = 0; i < VIA_NR_XVMC_LOCKS; ++i) { + lock = (volatile int *)XVMCLOCKPTR(dev_priv->sarea_priv, i); + if ((_DRM_LOCKING_CONTEXT(*lock) == context)) { + if (_DRM_LOCK_IS_HELD(*lock) + && (*lock & _DRM_LOCK_CONT)) { + wake_up(&(dev_priv->decoder_queue[i])); + } + *lock = 0; + } + } +} + +static int via_decoder_futex(struct drm_device *dev, void *data, struct drm_file *file_priv) +{ + drm_via_futex_t *fx = data; + volatile int *lock; + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + drm_via_sarea_t *sAPriv = dev_priv->sarea_priv; + int ret = 0; + + DRM_DEBUG("\n"); + + if (fx->lock >= VIA_NR_XVMC_LOCKS) + return -EFAULT; + + lock = (volatile int *)XVMCLOCKPTR(sAPriv, fx->lock); + + switch (fx->func) { + case VIA_FUTEX_WAIT: + VIA_WAIT_ON(ret, dev_priv->decoder_queue[fx->lock], + (fx->ms / 10) * (HZ / 100), *lock != fx->val); + return ret; + case VIA_FUTEX_WAKE: + wake_up(&(dev_priv->decoder_queue[fx->lock])); + return 0; + } + return 0; +} + +static int via_agp_init(struct drm_device *dev, void *data, struct drm_file *file_priv) +{ + drm_via_agp_t *agp = data; + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + + mutex_lock(&dev->struct_mutex); + drm_mm_init(&dev_priv->agp_mm, 0, agp->size >> VIA_MM_ALIGN_SHIFT); + + dev_priv->agp_initialized = 1; + dev_priv->agp_offset = agp->offset; + mutex_unlock(&dev->struct_mutex); + + DRM_DEBUG("offset = %u, size = %u\n", agp->offset, agp->size); + return 0; +} + +static int via_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv) +{ + drm_via_fb_t *fb = data; + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + + mutex_lock(&dev->struct_mutex); + drm_mm_init(&dev_priv->vram_mm, 0, fb->size >> VIA_MM_ALIGN_SHIFT); + + dev_priv->vram_initialized = 1; + dev_priv->vram_offset = fb->offset; + + mutex_unlock(&dev->struct_mutex); + DRM_DEBUG("offset = %u, size = %u\n", fb->offset, fb->size); + + return 0; + +} + +static int via_final_context(struct drm_device *dev, int context) +{ + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + + via_release_futex(dev_priv, context); + + /* Linux specific until context tracking code gets ported to BSD */ + /* Last context, perform cleanup */ + if (list_is_singular(&dev->ctxlist)) { + DRM_DEBUG("Last Context\n"); + drm_legacy_irq_uninstall(dev); + via_cleanup_futex(dev_priv); + via_do_cleanup_map(dev); + } + return 1; +} + +static void via_lastclose(struct drm_device *dev) +{ + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + + if (!dev_priv) + return; + + mutex_lock(&dev->struct_mutex); + if (dev_priv->vram_initialized) { + drm_mm_takedown(&dev_priv->vram_mm); + dev_priv->vram_initialized = 0; + } + if (dev_priv->agp_initialized) { + drm_mm_takedown(&dev_priv->agp_mm); + dev_priv->agp_initialized = 0; + } + mutex_unlock(&dev->struct_mutex); +} + +static int via_mem_alloc(struct drm_device *dev, void *data, + struct drm_file *file) +{ + drm_via_mem_t *mem = data; + int retval = 0, user_key; + struct via_memblock *item; + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + struct via_file_private *file_priv = file->driver_priv; + unsigned long tmpSize; + + if (mem->type > VIA_MEM_AGP) { + DRM_ERROR("Unknown memory type allocation\n"); + return -EINVAL; + } + mutex_lock(&dev->struct_mutex); + if (0 == ((mem->type == VIA_MEM_VIDEO) ? dev_priv->vram_initialized : + dev_priv->agp_initialized)) { + mutex_unlock(&dev->struct_mutex); + DRM_ERROR + ("Attempt to allocate from uninitialized memory manager.\n"); + return -EINVAL; + } + + item = kzalloc(sizeof(*item), GFP_KERNEL); + if (!item) { + retval = -ENOMEM; + goto fail_alloc; + } + + tmpSize = (mem->size + VIA_MM_ALIGN_MASK) >> VIA_MM_ALIGN_SHIFT; + if (mem->type == VIA_MEM_AGP) + retval = drm_mm_insert_node(&dev_priv->agp_mm, + &item->mm_node, + tmpSize); + else + retval = drm_mm_insert_node(&dev_priv->vram_mm, + &item->mm_node, + tmpSize); + if (retval) + goto fail_alloc; + + retval = idr_alloc(&dev_priv->object_idr, item, 1, 0, GFP_KERNEL); + if (retval < 0) + goto fail_idr; + user_key = retval; + + list_add(&item->owner_list, &file_priv->obj_list); + mutex_unlock(&dev->struct_mutex); + + mem->offset = ((mem->type == VIA_MEM_VIDEO) ? + dev_priv->vram_offset : dev_priv->agp_offset) + + ((item->mm_node.start) << VIA_MM_ALIGN_SHIFT); + mem->index = user_key; + + return 0; + +fail_idr: + drm_mm_remove_node(&item->mm_node); +fail_alloc: + kfree(item); + mutex_unlock(&dev->struct_mutex); + + mem->offset = 0; + mem->size = 0; + mem->index = 0; + DRM_DEBUG("Video memory allocation failed\n"); + + return retval; +} + +static int via_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv) +{ + drm_via_private_t *dev_priv = dev->dev_private; + drm_via_mem_t *mem = data; + struct via_memblock *obj; + + mutex_lock(&dev->struct_mutex); + obj = idr_find(&dev_priv->object_idr, mem->index); + if (obj == NULL) { + mutex_unlock(&dev->struct_mutex); + return -EINVAL; + } + + idr_remove(&dev_priv->object_idr, mem->index); + list_del(&obj->owner_list); + drm_mm_remove_node(&obj->mm_node); + kfree(obj); + mutex_unlock(&dev->struct_mutex); + + DRM_DEBUG("free = 0x%lx\n", mem->index); + + return 0; +} + + +static void via_reclaim_buffers_locked(struct drm_device *dev, + struct drm_file *file) +{ + struct via_file_private *file_priv = file->driver_priv; + struct via_memblock *entry, *next; + + if (!(dev->master && file->master->lock.hw_lock)) + return; + + drm_legacy_idlelock_take(&file->master->lock); + + mutex_lock(&dev->struct_mutex); + if (list_empty(&file_priv->obj_list)) { + mutex_unlock(&dev->struct_mutex); + drm_legacy_idlelock_release(&file->master->lock); + + return; + } + + via_driver_dma_quiescent(dev); + + list_for_each_entry_safe(entry, next, &file_priv->obj_list, + owner_list) { + list_del(&entry->owner_list); + drm_mm_remove_node(&entry->mm_node); + kfree(entry); + } + mutex_unlock(&dev->struct_mutex); + + drm_legacy_idlelock_release(&file->master->lock); + + return; +} + +static int via_do_init_map(struct drm_device *dev, drm_via_init_t *init) +{ + drm_via_private_t *dev_priv = dev->dev_private; + + DRM_DEBUG("\n"); + + dev_priv->sarea = drm_legacy_getsarea(dev); + if (!dev_priv->sarea) { + DRM_ERROR("could not find sarea!\n"); + dev->dev_private = (void *)dev_priv; + via_do_cleanup_map(dev); + return -EINVAL; + } + + dev_priv->fb = drm_legacy_findmap(dev, init->fb_offset); + if (!dev_priv->fb) { + DRM_ERROR("could not find framebuffer!\n"); + dev->dev_private = (void *)dev_priv; + via_do_cleanup_map(dev); + return -EINVAL; + } + dev_priv->mmio = drm_legacy_findmap(dev, init->mmio_offset); + if (!dev_priv->mmio) { + DRM_ERROR("could not find mmio region!\n"); + dev->dev_private = (void *)dev_priv; + via_do_cleanup_map(dev); + return -EINVAL; + } + + dev_priv->sarea_priv = + (drm_via_sarea_t *) ((u8 *) dev_priv->sarea->handle + + init->sarea_priv_offset); + + dev_priv->agpAddr = init->agpAddr; + + via_init_futex(dev_priv); + + via_init_dmablit(dev); + + dev->dev_private = (void *)dev_priv; + return 0; +} + +int via_do_cleanup_map(struct drm_device *dev) +{ + via_dma_cleanup(dev); + + return 0; +} + +static int via_map_init(struct drm_device *dev, void *data, struct drm_file *file_priv) +{ + drm_via_init_t *init = data; + + DRM_DEBUG("\n"); + + switch (init->func) { + case VIA_INIT_MAP: + return via_do_init_map(dev, init); + case VIA_CLEANUP_MAP: + return via_do_cleanup_map(dev); + } + + return -EINVAL; +} + +static int via_driver_load(struct drm_device *dev, unsigned long chipset) +{ + struct pci_dev *pdev = to_pci_dev(dev->dev); + drm_via_private_t *dev_priv; + int ret = 0; + + dev_priv = kzalloc(sizeof(drm_via_private_t), GFP_KERNEL); + if (dev_priv == NULL) + return -ENOMEM; + + idr_init_base(&dev_priv->object_idr, 1); + dev->dev_private = (void *)dev_priv; + + dev_priv->chipset = chipset; + + pci_set_master(pdev); + + ret = drm_vblank_init(dev, 1); + if (ret) { + kfree(dev_priv); + return ret; + } + + return 0; +} + +static void via_driver_unload(struct drm_device *dev) +{ + drm_via_private_t *dev_priv = dev->dev_private; + + idr_destroy(&dev_priv->object_idr); + + kfree(dev_priv); +} + +static void via_cmdbuf_start(drm_via_private_t *dev_priv); +static void via_cmdbuf_pause(drm_via_private_t *dev_priv); +static void via_cmdbuf_reset(drm_via_private_t *dev_priv); +static void via_cmdbuf_rewind(drm_via_private_t *dev_priv); +static int via_wait_idle(drm_via_private_t *dev_priv); +static void via_pad_cache(drm_via_private_t *dev_priv, int qwords); + +/* + * Free space in command buffer. + */ + +static uint32_t via_cmdbuf_space(drm_via_private_t *dev_priv) +{ + uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; + uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base; + + return ((hw_addr <= dev_priv->dma_low) ? + (dev_priv->dma_high + hw_addr - dev_priv->dma_low) : + (hw_addr - dev_priv->dma_low)); +} + +/* + * How much does the command regulator lag behind? + */ + +static uint32_t via_cmdbuf_lag(drm_via_private_t *dev_priv) +{ + uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; + uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base; + + return ((hw_addr <= dev_priv->dma_low) ? + (dev_priv->dma_low - hw_addr) : + (dev_priv->dma_wrap + dev_priv->dma_low - hw_addr)); +} + +/* + * Check that the given size fits in the buffer, otherwise wait. + */ + +static inline int +via_cmdbuf_wait(drm_via_private_t *dev_priv, unsigned int size) +{ + uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; + uint32_t cur_addr, hw_addr, next_addr; + volatile uint32_t *hw_addr_ptr; + uint32_t count; + hw_addr_ptr = dev_priv->hw_addr_ptr; + cur_addr = dev_priv->dma_low; + next_addr = cur_addr + size + 512 * 1024; + count = 1000000; + do { + hw_addr = *hw_addr_ptr - agp_base; + if (count-- == 0) { + DRM_ERROR + ("via_cmdbuf_wait timed out hw %x cur_addr %x next_addr %x\n", + hw_addr, cur_addr, next_addr); + return -1; + } + if ((cur_addr < hw_addr) && (next_addr >= hw_addr)) + msleep(1); + } while ((cur_addr < hw_addr) && (next_addr >= hw_addr)); + return 0; +} + +/* + * Checks whether buffer head has reach the end. Rewind the ring buffer + * when necessary. + * + * Returns virtual pointer to ring buffer. + */ + +static inline uint32_t *via_check_dma(drm_via_private_t * dev_priv, + unsigned int size) +{ + if ((dev_priv->dma_low + size + 4 * CMDBUF_ALIGNMENT_SIZE) > + dev_priv->dma_high) { + via_cmdbuf_rewind(dev_priv); + } + if (via_cmdbuf_wait(dev_priv, size) != 0) + return NULL; + + return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low); +} + +int via_dma_cleanup(struct drm_device *dev) +{ + if (dev->dev_private) { + drm_via_private_t *dev_priv = + (drm_via_private_t *) dev->dev_private; + + if (dev_priv->ring.virtual_start) { + via_cmdbuf_reset(dev_priv); + + drm_legacy_ioremapfree(&dev_priv->ring.map, dev); + dev_priv->ring.virtual_start = NULL; + } + + } + + return 0; +} + +static int via_initialize(struct drm_device *dev, + drm_via_private_t *dev_priv, + drm_via_dma_init_t *init) +{ + if (!dev_priv || !dev_priv->mmio) { + DRM_ERROR("via_dma_init called before via_map_init\n"); + return -EFAULT; + } + + if (dev_priv->ring.virtual_start != NULL) { + DRM_ERROR("called again without calling cleanup\n"); + return -EFAULT; + } + + if (!dev->agp || !dev->agp->base) { + DRM_ERROR("called with no agp memory available\n"); + return -EFAULT; + } + + if (dev_priv->chipset == VIA_DX9_0) { + DRM_ERROR("AGP DMA is not supported on this chip\n"); + return -EINVAL; + } + + dev_priv->ring.map.offset = dev->agp->base + init->offset; + dev_priv->ring.map.size = init->size; + dev_priv->ring.map.type = 0; + dev_priv->ring.map.flags = 0; + dev_priv->ring.map.mtrr = 0; + + drm_legacy_ioremap(&dev_priv->ring.map, dev); + + if (dev_priv->ring.map.handle == NULL) { + via_dma_cleanup(dev); + DRM_ERROR("can not ioremap virtual address for" + " ring buffer\n"); + return -ENOMEM; + } + + dev_priv->ring.virtual_start = dev_priv->ring.map.handle; + + dev_priv->dma_ptr = dev_priv->ring.virtual_start; + dev_priv->dma_low = 0; + dev_priv->dma_high = init->size; + dev_priv->dma_wrap = init->size; + dev_priv->dma_offset = init->offset; + dev_priv->last_pause_ptr = NULL; + dev_priv->hw_addr_ptr = + (volatile uint32_t *)((char *)dev_priv->mmio->handle + + init->reg_pause_addr); + + via_cmdbuf_start(dev_priv); + + return 0; +} + +static int via_dma_init(struct drm_device *dev, void *data, struct drm_file *file_priv) +{ + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + drm_via_dma_init_t *init = data; + int retcode = 0; + + switch (init->func) { + case VIA_INIT_DMA: + if (!capable(CAP_SYS_ADMIN)) + retcode = -EPERM; + else + retcode = via_initialize(dev, dev_priv, init); + break; + case VIA_CLEANUP_DMA: + if (!capable(CAP_SYS_ADMIN)) + retcode = -EPERM; + else + retcode = via_dma_cleanup(dev); + break; + case VIA_DMA_INITIALIZED: + retcode = (dev_priv->ring.virtual_start != NULL) ? + 0 : -EFAULT; + break; + default: + retcode = -EINVAL; + break; + } + + return retcode; +} + +static int via_dispatch_cmdbuffer(struct drm_device *dev, drm_via_cmdbuffer_t *cmd) +{ + drm_via_private_t *dev_priv; + uint32_t *vb; + int ret; + + dev_priv = (drm_via_private_t *) dev->dev_private; + + if (dev_priv->ring.virtual_start == NULL) { + DRM_ERROR("called without initializing AGP ring buffer.\n"); + return -EFAULT; + } + + if (cmd->size > VIA_PCI_BUF_SIZE) + return -ENOMEM; + + if (copy_from_user(dev_priv->pci_buf, cmd->buf, cmd->size)) + return -EFAULT; + + /* + * Running this function on AGP memory is dead slow. Therefore + * we run it on a temporary cacheable system memory buffer and + * copy it to AGP memory when ready. + */ + + if ((ret = + via_verify_command_stream((uint32_t *) dev_priv->pci_buf, + cmd->size, dev, 1))) { + return ret; + } + + vb = via_check_dma(dev_priv, (cmd->size < 0x100) ? 0x102 : cmd->size); + if (vb == NULL) + return -EAGAIN; + + memcpy(vb, dev_priv->pci_buf, cmd->size); + + dev_priv->dma_low += cmd->size; + + /* + * Small submissions somehow stalls the CPU. (AGP cache effects?) + * pad to greater size. + */ + + if (cmd->size < 0x100) + via_pad_cache(dev_priv, (0x100 - cmd->size) >> 3); + via_cmdbuf_pause(dev_priv); + + return 0; +} + +int via_driver_dma_quiescent(struct drm_device *dev) +{ + drm_via_private_t *dev_priv = dev->dev_private; + + if (!via_wait_idle(dev_priv)) + return -EBUSY; + return 0; +} + +static int via_flush_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) +{ + + LOCK_TEST_WITH_RETURN(dev, file_priv); + + return via_driver_dma_quiescent(dev); +} + +static int via_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv) +{ + drm_via_cmdbuffer_t *cmdbuf = data; + int ret; + + LOCK_TEST_WITH_RETURN(dev, file_priv); + + DRM_DEBUG("buf %p size %lu\n", cmdbuf->buf, cmdbuf->size); + + ret = via_dispatch_cmdbuffer(dev, cmdbuf); + return ret; +} + +static int via_dispatch_pci_cmdbuffer(struct drm_device *dev, + drm_via_cmdbuffer_t *cmd) +{ + drm_via_private_t *dev_priv = dev->dev_private; + int ret; + + if (cmd->size > VIA_PCI_BUF_SIZE) + return -ENOMEM; + if (copy_from_user(dev_priv->pci_buf, cmd->buf, cmd->size)) + return -EFAULT; + + if ((ret = + via_verify_command_stream((uint32_t *) dev_priv->pci_buf, + cmd->size, dev, 0))) { + return ret; + } + + ret = + via_parse_command_stream(dev, (const uint32_t *)dev_priv->pci_buf, + cmd->size); + return ret; +} + +static int via_pci_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv) +{ + drm_via_cmdbuffer_t *cmdbuf = data; + int ret; + + LOCK_TEST_WITH_RETURN(dev, file_priv); + + DRM_DEBUG("buf %p size %lu\n", cmdbuf->buf, cmdbuf->size); + + ret = via_dispatch_pci_cmdbuffer(dev, cmdbuf); + return ret; +} + +static inline uint32_t *via_align_buffer(drm_via_private_t *dev_priv, + uint32_t * vb, int qw_count) +{ + for (; qw_count > 0; --qw_count) + VIA_OUT_RING_QW(HC_DUMMY, HC_DUMMY); + return vb; +} + +/* + * This function is used internally by ring buffer management code. + * + * Returns virtual pointer to ring buffer. + */ +static inline uint32_t *via_get_dma(drm_via_private_t *dev_priv) +{ + return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low); +} + +/* + * Hooks a segment of data into the tail of the ring-buffer by + * modifying the pause address stored in the buffer itself. If + * the regulator has already paused, restart it. + */ +static int via_hook_segment(drm_via_private_t *dev_priv, + uint32_t pause_addr_hi, uint32_t pause_addr_lo, + int no_pci_fire) +{ + int paused, count; + volatile uint32_t *paused_at = dev_priv->last_pause_ptr; + uint32_t reader, ptr; + uint32_t diff; + + paused = 0; + via_flush_write_combine(); + (void) *(volatile uint32_t *)(via_get_dma(dev_priv) - 1); + + *paused_at = pause_addr_lo; + via_flush_write_combine(); + (void) *paused_at; + + reader = *(dev_priv->hw_addr_ptr); + ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) + + dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4; + + dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1; + + /* + * If there is a possibility that the command reader will + * miss the new pause address and pause on the old one, + * In that case we need to program the new start address + * using PCI. + */ + + diff = (uint32_t) (ptr - reader) - dev_priv->dma_diff; + count = 10000000; + while (diff == 0 && count--) { + paused = (via_read(dev_priv, 0x41c) & 0x80000000); + if (paused) + break; + reader = *(dev_priv->hw_addr_ptr); + diff = (uint32_t) (ptr - reader) - dev_priv->dma_diff; + } + + paused = via_read(dev_priv, 0x41c) & 0x80000000; + + if (paused && !no_pci_fire) { + reader = *(dev_priv->hw_addr_ptr); + diff = (uint32_t) (ptr - reader) - dev_priv->dma_diff; + diff &= (dev_priv->dma_high - 1); + if (diff != 0 && diff < (dev_priv->dma_high >> 1)) { + DRM_ERROR("Paused at incorrect address. " + "0x%08x, 0x%08x 0x%08x\n", + ptr, reader, dev_priv->dma_diff); + } else if (diff == 0) { + /* + * There is a concern that these writes may stall the PCI bus + * if the GPU is not idle. However, idling the GPU first + * doesn't make a difference. + */ + + via_write(dev_priv, VIA_REG_TRANSET, (HC_ParaType_PreCR << 16)); + via_write(dev_priv, VIA_REG_TRANSPACE, pause_addr_hi); + via_write(dev_priv, VIA_REG_TRANSPACE, pause_addr_lo); + via_read(dev_priv, VIA_REG_TRANSPACE); + } + } + return paused; +} + +static int via_wait_idle(drm_via_private_t *dev_priv) +{ + int count = 10000000; + + while (!(via_read(dev_priv, VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY) && --count) + ; + + while (count && (via_read(dev_priv, VIA_REG_STATUS) & + (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | + VIA_3D_ENG_BUSY))) + --count; + return count; +} + +static uint32_t *via_align_cmd(drm_via_private_t *dev_priv, uint32_t cmd_type, + uint32_t addr, uint32_t *cmd_addr_hi, + uint32_t *cmd_addr_lo, int skip_wait) +{ + uint32_t agp_base; + uint32_t cmd_addr, addr_lo, addr_hi; + uint32_t *vb; + uint32_t qw_pad_count; + + if (!skip_wait) + via_cmdbuf_wait(dev_priv, 2 * CMDBUF_ALIGNMENT_SIZE); + + vb = via_get_dma(dev_priv); + VIA_OUT_RING_QW(HC_HEADER2 | ((VIA_REG_TRANSET >> 2) << 12) | + (VIA_REG_TRANSPACE >> 2), HC_ParaType_PreCR << 16); + agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; + qw_pad_count = (CMDBUF_ALIGNMENT_SIZE >> 3) - + ((dev_priv->dma_low & CMDBUF_ALIGNMENT_MASK) >> 3); + + cmd_addr = (addr) ? addr : + agp_base + dev_priv->dma_low - 8 + (qw_pad_count << 3); + addr_lo = ((HC_SubA_HAGPBpL << 24) | (cmd_type & HC_HAGPBpID_MASK) | + (cmd_addr & HC_HAGPBpL_MASK)); + addr_hi = ((HC_SubA_HAGPBpH << 24) | (cmd_addr >> 24)); + + vb = via_align_buffer(dev_priv, vb, qw_pad_count - 1); + VIA_OUT_RING_QW(*cmd_addr_hi = addr_hi, *cmd_addr_lo = addr_lo); + return vb; +} + +static void via_cmdbuf_start(drm_via_private_t *dev_priv) +{ + uint32_t pause_addr_lo, pause_addr_hi; + uint32_t start_addr, start_addr_lo; + uint32_t end_addr, end_addr_lo; + uint32_t command; + uint32_t agp_base; + uint32_t ptr; + uint32_t reader; + int count; + + dev_priv->dma_low = 0; + + agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; + start_addr = agp_base; + end_addr = agp_base + dev_priv->dma_high; + + start_addr_lo = ((HC_SubA_HAGPBstL << 24) | (start_addr & 0xFFFFFF)); + end_addr_lo = ((HC_SubA_HAGPBendL << 24) | (end_addr & 0xFFFFFF)); + command = ((HC_SubA_HAGPCMNT << 24) | (start_addr >> 24) | + ((end_addr & 0xff000000) >> 16)); + + dev_priv->last_pause_ptr = + via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, + &pause_addr_hi, &pause_addr_lo, 1) - 1; + + via_flush_write_combine(); + (void) *(volatile uint32_t *)dev_priv->last_pause_ptr; + + via_write(dev_priv, VIA_REG_TRANSET, (HC_ParaType_PreCR << 16)); + via_write(dev_priv, VIA_REG_TRANSPACE, command); + via_write(dev_priv, VIA_REG_TRANSPACE, start_addr_lo); + via_write(dev_priv, VIA_REG_TRANSPACE, end_addr_lo); + + via_write(dev_priv, VIA_REG_TRANSPACE, pause_addr_hi); + via_write(dev_priv, VIA_REG_TRANSPACE, pause_addr_lo); + wmb(); + via_write(dev_priv, VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK); + via_read(dev_priv, VIA_REG_TRANSPACE); + + dev_priv->dma_diff = 0; + + count = 10000000; + while (!(via_read(dev_priv, 0x41c) & 0x80000000) && count--); + + reader = *(dev_priv->hw_addr_ptr); + ptr = ((volatile char *)dev_priv->last_pause_ptr - dev_priv->dma_ptr) + + dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4; + + /* + * This is the difference between where we tell the + * command reader to pause and where it actually pauses. + * This differs between hw implementation so we need to + * detect it. + */ + + dev_priv->dma_diff = ptr - reader; +} + +static void via_pad_cache(drm_via_private_t *dev_priv, int qwords) +{ + uint32_t *vb; + + via_cmdbuf_wait(dev_priv, qwords + 2); + vb = via_get_dma(dev_priv); + VIA_OUT_RING_QW(HC_HEADER2, HC_ParaType_NotTex << 16); + via_align_buffer(dev_priv, vb, qwords); +} + +static inline void via_dummy_bitblt(drm_via_private_t *dev_priv) +{ + uint32_t *vb = via_get_dma(dev_priv); + SetReg2DAGP(0x0C, (0 | (0 << 16))); + SetReg2DAGP(0x10, 0 | (0 << 16)); + SetReg2DAGP(0x0, 0x1 | 0x2000 | 0xAA000000); +} + +static void via_cmdbuf_jump(drm_via_private_t *dev_priv) +{ + uint32_t pause_addr_lo, pause_addr_hi; + uint32_t jump_addr_lo, jump_addr_hi; + volatile uint32_t *last_pause_ptr; + uint32_t dma_low_save1, dma_low_save2; + + via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi, + &jump_addr_lo, 0); + + dev_priv->dma_wrap = dev_priv->dma_low; + + /* + * Wrap command buffer to the beginning. + */ + + dev_priv->dma_low = 0; + if (via_cmdbuf_wait(dev_priv, CMDBUF_ALIGNMENT_SIZE) != 0) + DRM_ERROR("via_cmdbuf_jump failed\n"); + + via_dummy_bitblt(dev_priv); + via_dummy_bitblt(dev_priv); + + last_pause_ptr = + via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, + &pause_addr_lo, 0) - 1; + via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, + &pause_addr_lo, 0); + + *last_pause_ptr = pause_addr_lo; + dma_low_save1 = dev_priv->dma_low; + + /* + * Now, set a trap that will pause the regulator if it tries to rerun the old + * command buffer. (Which may happen if via_hook_segment detecs a command regulator pause + * and reissues the jump command over PCI, while the regulator has already taken the jump + * and actually paused at the current buffer end). + * There appears to be no other way to detect this condition, since the hw_addr_pointer + * does not seem to get updated immediately when a jump occurs. + */ + + last_pause_ptr = + via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, + &pause_addr_lo, 0) - 1; + via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, + &pause_addr_lo, 0); + *last_pause_ptr = pause_addr_lo; + + dma_low_save2 = dev_priv->dma_low; + dev_priv->dma_low = dma_low_save1; + via_hook_segment(dev_priv, jump_addr_hi, jump_addr_lo, 0); + dev_priv->dma_low = dma_low_save2; + via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0); +} + + +static void via_cmdbuf_rewind(drm_via_private_t *dev_priv) +{ + via_cmdbuf_jump(dev_priv); +} + +static void via_cmdbuf_flush(drm_via_private_t *dev_priv, uint32_t cmd_type) +{ + uint32_t pause_addr_lo, pause_addr_hi; + + via_align_cmd(dev_priv, cmd_type, 0, &pause_addr_hi, &pause_addr_lo, 0); + via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0); +} + +static void via_cmdbuf_pause(drm_via_private_t *dev_priv) +{ + via_cmdbuf_flush(dev_priv, HC_HAGPBpID_PAUSE); +} + +static void via_cmdbuf_reset(drm_via_private_t *dev_priv) +{ + via_cmdbuf_flush(dev_priv, HC_HAGPBpID_STOP); + via_wait_idle(dev_priv); +} + +/* + * User interface to the space and lag functions. + */ + +static int via_cmdbuf_size(struct drm_device *dev, void *data, struct drm_file *file_priv) +{ + drm_via_cmdbuf_size_t *d_siz = data; + int ret = 0; + uint32_t tmp_size, count; + drm_via_private_t *dev_priv; + + DRM_DEBUG("\n"); + LOCK_TEST_WITH_RETURN(dev, file_priv); + + dev_priv = (drm_via_private_t *) dev->dev_private; + + if (dev_priv->ring.virtual_start == NULL) { + DRM_ERROR("called without initializing AGP ring buffer.\n"); + return -EFAULT; + } + + count = 1000000; + tmp_size = d_siz->size; + switch (d_siz->func) { + case VIA_CMDBUF_SPACE: + while (((tmp_size = via_cmdbuf_space(dev_priv)) < d_siz->size) + && --count) { + if (!d_siz->wait) + break; + } + if (!count) { + DRM_ERROR("VIA_CMDBUF_SPACE timed out.\n"); + ret = -EAGAIN; + } + break; + case VIA_CMDBUF_LAG: + while (((tmp_size = via_cmdbuf_lag(dev_priv)) > d_siz->size) + && --count) { + if (!d_siz->wait) + break; + } + if (!count) { + DRM_ERROR("VIA_CMDBUF_LAG timed out.\n"); + ret = -EAGAIN; + } + break; + default: + ret = -EFAULT; + } + d_siz->size = tmp_size; + + return ret; +} + +static const struct drm_ioctl_desc via_ioctls[] = { + DRM_IOCTL_DEF_DRV(VIA_ALLOCMEM, via_mem_alloc, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_FREEMEM, via_mem_free, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_AGP_INIT, via_agp_init, DRM_AUTH|DRM_MASTER), + DRM_IOCTL_DEF_DRV(VIA_FB_INIT, via_fb_init, DRM_AUTH|DRM_MASTER), + DRM_IOCTL_DEF_DRV(VIA_MAP_INIT, via_map_init, DRM_AUTH|DRM_MASTER), + DRM_IOCTL_DEF_DRV(VIA_DEC_FUTEX, via_decoder_futex, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_DMA_INIT, via_dma_init, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_CMDBUFFER, via_cmdbuffer, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_FLUSH, via_flush_ioctl, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_PCICMD, via_pci_cmdbuffer, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_CMDBUF_SIZE, via_cmdbuf_size, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_WAIT_IRQ, via_wait_irq, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_DMA_BLIT, via_dma_blit, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_BLIT_SYNC, via_dma_blit_sync, DRM_AUTH) +}; + +static int via_max_ioctl = ARRAY_SIZE(via_ioctls); +static int via_driver_open(struct drm_device *dev, struct drm_file *file) +{ + struct via_file_private *file_priv; + + DRM_DEBUG_DRIVER("\n"); + file_priv = kmalloc(sizeof(*file_priv), GFP_KERNEL); + if (!file_priv) + return -ENOMEM; + + file->driver_priv = file_priv; + + INIT_LIST_HEAD(&file_priv->obj_list); + + return 0; +} + +static void via_driver_postclose(struct drm_device *dev, struct drm_file *file) +{ + struct via_file_private *file_priv = file->driver_priv; + + kfree(file_priv); +} + +static struct pci_device_id pciidlist[] = { + viadrv_PCI_IDS +}; + +static const struct file_operations via_driver_fops = { + .owner = THIS_MODULE, + .open = drm_open, + .release = drm_release, + .unlocked_ioctl = drm_ioctl, + .mmap = drm_legacy_mmap, + .poll = drm_poll, + .compat_ioctl = drm_compat_ioctl, + .llseek = noop_llseek, +}; + +static struct drm_driver driver = { + .driver_features = + DRIVER_USE_AGP | DRIVER_HAVE_IRQ | DRIVER_LEGACY, + .load = via_driver_load, + .unload = via_driver_unload, + .open = via_driver_open, + .preclose = via_reclaim_buffers_locked, + .postclose = via_driver_postclose, + .context_dtor = via_final_context, + .get_vblank_counter = via_get_vblank_counter, + .enable_vblank = via_enable_vblank, + .disable_vblank = via_disable_vblank, + .irq_preinstall = via_driver_irq_preinstall, + .irq_postinstall = via_driver_irq_postinstall, + .irq_uninstall = via_driver_irq_uninstall, + .irq_handler = via_driver_irq_handler, + .dma_quiescent = via_driver_dma_quiescent, + .lastclose = via_lastclose, + .ioctls = via_ioctls, + .fops = &via_driver_fops, + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, +}; + +static struct pci_driver via_pci_driver = { + .name = DRIVER_NAME, + .id_table = pciidlist, +}; + +static int __init via_init(void) +{ + driver.num_ioctls = via_max_ioctl; + via_init_command_verifier(); + return drm_legacy_pci_init(&driver, &via_pci_driver); +} + +static void __exit via_exit(void) +{ + drm_legacy_pci_exit(&driver, &via_pci_driver); +} + +module_init(via_init); +module_exit(via_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/gpu/drm/via/via_drv.c b/drivers/gpu/drm/via/via_drv.c deleted file mode 100644 index 5da38082821f..000000000000 --- a/drivers/gpu/drm/via/via_drv.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. - * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sub license, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include <linux/module.h> -#include <linux/pci.h> - -#include <drm/drm_drv.h> -#include <drm/drm_file.h> -#include <drm/drm_pciids.h> -#include <drm/via_drm.h> - -#include "via_drv.h" - - -static int via_driver_open(struct drm_device *dev, struct drm_file *file) -{ - struct via_file_private *file_priv; - - DRM_DEBUG_DRIVER("\n"); - file_priv = kmalloc(sizeof(*file_priv), GFP_KERNEL); - if (!file_priv) - return -ENOMEM; - - file->driver_priv = file_priv; - - INIT_LIST_HEAD(&file_priv->obj_list); - - return 0; -} - -static void via_driver_postclose(struct drm_device *dev, struct drm_file *file) -{ - struct via_file_private *file_priv = file->driver_priv; - - kfree(file_priv); -} - -static struct pci_device_id pciidlist[] = { - viadrv_PCI_IDS -}; - -static const struct file_operations via_driver_fops = { - .owner = THIS_MODULE, - .open = drm_open, - .release = drm_release, - .unlocked_ioctl = drm_ioctl, - .mmap = drm_legacy_mmap, - .poll = drm_poll, - .compat_ioctl = drm_compat_ioctl, - .llseek = noop_llseek, -}; - -static struct drm_driver driver = { - .driver_features = - DRIVER_USE_AGP | DRIVER_HAVE_IRQ | DRIVER_LEGACY, - .load = via_driver_load, - .unload = via_driver_unload, - .open = via_driver_open, - .preclose = via_reclaim_buffers_locked, - .postclose = via_driver_postclose, - .context_dtor = via_final_context, - .get_vblank_counter = via_get_vblank_counter, - .enable_vblank = via_enable_vblank, - .disable_vblank = via_disable_vblank, - .irq_preinstall = via_driver_irq_preinstall, - .irq_postinstall = via_driver_irq_postinstall, - .irq_uninstall = via_driver_irq_uninstall, - .irq_handler = via_driver_irq_handler, - .dma_quiescent = via_driver_dma_quiescent, - .lastclose = via_lastclose, - .ioctls = via_ioctls, - .fops = &via_driver_fops, - .name = DRIVER_NAME, - .desc = DRIVER_DESC, - .date = DRIVER_DATE, - .major = DRIVER_MAJOR, - .minor = DRIVER_MINOR, - .patchlevel = DRIVER_PATCHLEVEL, -}; - -static struct pci_driver via_pci_driver = { - .name = DRIVER_NAME, - .id_table = pciidlist, -}; - -static int __init via_init(void) -{ - driver.num_ioctls = via_max_ioctl; - via_init_command_verifier(); - return drm_legacy_pci_init(&driver, &via_pci_driver); -} - -static void __exit via_exit(void) -{ - drm_legacy_pci_exit(&driver, &via_pci_driver); -} - -module_init(via_init); -module_exit(via_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/gpu/drm/via/via_drv.h b/drivers/gpu/drm/via/via_drv.h deleted file mode 100644 index d5ad1b05bf77..000000000000 --- a/drivers/gpu/drm/via/via_drv.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. - * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sub license, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ -#ifndef _VIA_DRV_H_ -#define _VIA_DRV_H_ - -#include <linux/irqreturn.h> -#include <linux/jiffies.h> -#include <linux/sched.h> -#include <linux/sched/signal.h> -#include <linux/wait.h> - -#include <drm/drm_ioctl.h> -#include <drm/drm_legacy.h> -#include <drm/drm_mm.h> -#include <drm/via_drm.h> - -#define DRIVER_AUTHOR "Various" - -#define DRIVER_NAME "via" -#define DRIVER_DESC "VIA Unichrome / Pro" -#define DRIVER_DATE "20070202" - -#define DRIVER_MAJOR 2 -#define DRIVER_MINOR 11 -#define DRIVER_PATCHLEVEL 1 - -#include "via_verifier.h" - -#include "via_dmablit.h" - -#define VIA_PCI_BUF_SIZE 60000 -#define VIA_FIRE_BUF_SIZE 1024 -#define VIA_NUM_IRQS 4 - -typedef struct drm_via_ring_buffer { - drm_local_map_t map; - char *virtual_start; -} drm_via_ring_buffer_t; - -typedef uint32_t maskarray_t[5]; - -typedef struct drm_via_irq { - atomic_t irq_received; - uint32_t pending_mask; - uint32_t enable_mask; - wait_queue_head_t irq_queue; -} drm_via_irq_t; - -typedef struct drm_via_private { - drm_via_sarea_t *sarea_priv; - drm_local_map_t *sarea; - drm_local_map_t *fb; - drm_local_map_t *mmio; - unsigned long agpAddr; - wait_queue_head_t decoder_queue[VIA_NR_XVMC_LOCKS]; - char *dma_ptr; - unsigned int dma_low; - unsigned int dma_high; - unsigned int dma_offset; - uint32_t dma_wrap; - volatile uint32_t *last_pause_ptr; - volatile uint32_t *hw_addr_ptr; - drm_via_ring_buffer_t ring; - ktime_t last_vblank; - int last_vblank_valid; - ktime_t nsec_per_vblank; - atomic_t vbl_received; - drm_via_state_t hc_state; - char pci_buf[VIA_PCI_BUF_SIZE]; - const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE]; - uint32_t num_fire_offsets; - int chipset; - drm_via_irq_t via_irqs[VIA_NUM_IRQS]; - unsigned num_irqs; - maskarray_t *irq_masks; - uint32_t irq_enable_mask; - uint32_t irq_pending_mask; - int *irq_map; - unsigned int idle_fault; - int vram_initialized; - struct drm_mm vram_mm; - int agp_initialized; - struct drm_mm agp_mm; - /** Mapping of userspace keys to mm objects */ - struct idr object_idr; - unsigned long vram_offset; - unsigned long agp_offset; - drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES]; - uint32_t dma_diff; -} drm_via_private_t; - -struct via_file_private { - struct list_head obj_list; -}; - -enum via_family { - VIA_OTHER = 0, /* Baseline */ - VIA_PRO_GROUP_A, /* Another video engine and DMA commands */ - VIA_DX9_0 /* Same video as pro_group_a, but 3D is unsupported */ -}; - -/* VIA MMIO register access */ -static inline u32 via_read(struct drm_via_private *dev_priv, u32 reg) -{ - return readl((void __iomem *)(dev_priv->mmio->handle + reg)); -} - -static inline void via_write(struct drm_via_private *dev_priv, u32 reg, - u32 val) -{ - writel(val, (void __iomem *)(dev_priv->mmio->handle + reg)); -} - -static inline void via_write8(struct drm_via_private *dev_priv, u32 reg, - u32 val) -{ - writeb(val, (void __iomem *)(dev_priv->mmio->handle + reg)); -} - -static inline void via_write8_mask(struct drm_via_private *dev_priv, - u32 reg, u32 mask, u32 val) -{ - u32 tmp; - - tmp = readb((void __iomem *)(dev_priv->mmio->handle + reg)); - tmp = (tmp & ~mask) | (val & mask); - writeb(tmp, (void __iomem *)(dev_priv->mmio->handle + reg)); -} - -/* - * Poll in a loop waiting for 'contidition' to be true. - * Note: A direct replacement with wait_event_interruptible_timeout() - * will not work unless driver is updated to emit wake_up() - * in relevant places that can impact the 'condition' - * - * Returns: - * ret keeps current value if 'condition' becomes true - * ret = -BUSY if timeout happens - * ret = -EINTR if a signal interrupted the waiting period - */ -#define VIA_WAIT_ON( ret, queue, timeout, condition ) \ -do { \ - DECLARE_WAITQUEUE(entry, current); \ - unsigned long end = jiffies + (timeout); \ - add_wait_queue(&(queue), &entry); \ - \ - for (;;) { \ - __set_current_state(TASK_INTERRUPTIBLE); \ - if (condition) \ - break; \ - if (time_after_eq(jiffies, end)) { \ - ret = -EBUSY; \ - break; \ - } \ - schedule_timeout((HZ/100 > 1) ? HZ/100 : 1); \ - if (signal_pending(current)) { \ - ret = -EINTR; \ - break; \ - } \ - } \ - __set_current_state(TASK_RUNNING); \ - remove_wait_queue(&(queue), &entry); \ -} while (0) - -extern const struct drm_ioctl_desc via_ioctls[]; -extern int via_max_ioctl; - -extern int via_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int via_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int via_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int via_agp_init(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int via_map_init(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int via_decoder_futex(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int via_dma_blit_sync(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int via_dma_blit(struct drm_device *dev, void *data, struct drm_file *file_priv); - -extern int via_driver_load(struct drm_device *dev, unsigned long chipset); -extern void via_driver_unload(struct drm_device *dev); - -extern int via_init_context(struct drm_device *dev, int context); -extern int via_final_context(struct drm_device *dev, int context); - -extern int via_do_cleanup_map(struct drm_device *dev); -extern u32 via_get_vblank_counter(struct drm_device *dev, unsigned int pipe); -extern int via_enable_vblank(struct drm_device *dev, unsigned int pipe); -extern void via_disable_vblank(struct drm_device *dev, unsigned int pipe); - -extern irqreturn_t via_driver_irq_handler(int irq, void *arg); -extern void via_driver_irq_preinstall(struct drm_device *dev); -extern int via_driver_irq_postinstall(struct drm_device *dev); -extern void via_driver_irq_uninstall(struct drm_device *dev); - -extern int via_dma_cleanup(struct drm_device *dev); -extern void via_init_command_verifier(void); -extern int via_driver_dma_quiescent(struct drm_device *dev); -extern void via_init_futex(drm_via_private_t *dev_priv); -extern void via_cleanup_futex(drm_via_private_t *dev_priv); -extern void via_release_futex(drm_via_private_t *dev_priv, int context); - -extern void via_reclaim_buffers_locked(struct drm_device *dev, - struct drm_file *file_priv); -extern void via_lastclose(struct drm_device *dev); - -extern void via_dmablit_handler(struct drm_device *dev, int engine, int from_irq); -extern void via_init_dmablit(struct drm_device *dev); - -#endif diff --git a/drivers/gpu/drm/via/via_irq.c b/drivers/gpu/drm/via/via_irq.c deleted file mode 100644 index faeae5d881fb..000000000000 --- a/drivers/gpu/drm/via/via_irq.c +++ /dev/null @@ -1,388 +0,0 @@ -/* via_irq.c - * - * Copyright 2004 BEAM Ltd. - * Copyright 2002 Tungsten Graphics, Inc. - * Copyright 2005 Thomas Hellstrom. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BEAM LTD, TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Authors: - * Terry Barnaby <terry1@beam.ltd.uk> - * Keith Whitwell <keith@tungstengraphics.com> - * Thomas Hellstrom <unichrome@shipmail.org> - * - * This code provides standard DRM access to the Via Unichrome / Pro Vertical blank - * interrupt, as well as an infrastructure to handle other interrupts of the chip. - * The refresh rate is also calculated for video playback sync purposes. - */ - -#include <drm/drm_device.h> -#include <drm/drm_vblank.h> -#include <drm/via_drm.h> - -#include "via_drv.h" - -#define VIA_REG_INTERRUPT 0x200 - -/* VIA_REG_INTERRUPT */ -#define VIA_IRQ_GLOBAL (1 << 31) -#define VIA_IRQ_VBLANK_ENABLE (1 << 19) -#define VIA_IRQ_VBLANK_PENDING (1 << 3) -#define VIA_IRQ_HQV0_ENABLE (1 << 11) -#define VIA_IRQ_HQV1_ENABLE (1 << 25) -#define VIA_IRQ_HQV0_PENDING (1 << 9) -#define VIA_IRQ_HQV1_PENDING (1 << 10) -#define VIA_IRQ_DMA0_DD_ENABLE (1 << 20) -#define VIA_IRQ_DMA0_TD_ENABLE (1 << 21) -#define VIA_IRQ_DMA1_DD_ENABLE (1 << 22) -#define VIA_IRQ_DMA1_TD_ENABLE (1 << 23) -#define VIA_IRQ_DMA0_DD_PENDING (1 << 4) -#define VIA_IRQ_DMA0_TD_PENDING (1 << 5) -#define VIA_IRQ_DMA1_DD_PENDING (1 << 6) -#define VIA_IRQ_DMA1_TD_PENDING (1 << 7) - - -/* - * Device-specific IRQs go here. This type might need to be extended with - * the register if there are multiple IRQ control registers. - * Currently we activate the HQV interrupts of Unichrome Pro group A. - */ - -static maskarray_t via_pro_group_a_irqs[] = { - {VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010, - 0x00000000 }, - {VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010, - 0x00000000 }, - {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0, - VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, - {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1, - VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, -}; -static int via_num_pro_group_a = ARRAY_SIZE(via_pro_group_a_irqs); -static int via_irqmap_pro_group_a[] = {0, 1, -1, 2, -1, 3}; - -static maskarray_t via_unichrome_irqs[] = { - {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0, - VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, - {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1, - VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008} -}; -static int via_num_unichrome = ARRAY_SIZE(via_unichrome_irqs); -static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1}; - - -u32 via_get_vblank_counter(struct drm_device *dev, unsigned int pipe) -{ - drm_via_private_t *dev_priv = dev->dev_private; - - if (pipe != 0) - return 0; - - return atomic_read(&dev_priv->vbl_received); -} - -irqreturn_t via_driver_irq_handler(int irq, void *arg) -{ - struct drm_device *dev = (struct drm_device *) arg; - drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; - u32 status; - int handled = 0; - ktime_t cur_vblank; - drm_via_irq_t *cur_irq = dev_priv->via_irqs; - int i; - - status = via_read(dev_priv, VIA_REG_INTERRUPT); - if (status & VIA_IRQ_VBLANK_PENDING) { - atomic_inc(&dev_priv->vbl_received); - if (!(atomic_read(&dev_priv->vbl_received) & 0x0F)) { - cur_vblank = ktime_get(); - if (dev_priv->last_vblank_valid) { - dev_priv->nsec_per_vblank = - ktime_sub(cur_vblank, - dev_priv->last_vblank) >> 4; - } - dev_priv->last_vblank = cur_vblank; - dev_priv->last_vblank_valid = 1; - } - if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) { - DRM_DEBUG("nsec per vblank is: %llu\n", - ktime_to_ns(dev_priv->nsec_per_vblank)); - } - drm_handle_vblank(dev, 0); - handled = 1; - } - - for (i = 0; i < dev_priv->num_irqs; ++i) { - if (status & cur_irq->pending_mask) { - atomic_inc(&cur_irq->irq_received); - wake_up(&cur_irq->irq_queue); - handled = 1; - if (dev_priv->irq_map[drm_via_irq_dma0_td] == i) - via_dmablit_handler(dev, 0, 1); - else if (dev_priv->irq_map[drm_via_irq_dma1_td] == i) - via_dmablit_handler(dev, 1, 1); - } - cur_irq++; - } - - /* Acknowledge interrupts */ - via_write(dev_priv, VIA_REG_INTERRUPT, status); - - - if (handled) - return IRQ_HANDLED; - else - return IRQ_NONE; -} - -static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t *dev_priv) -{ - u32 status; - - if (dev_priv) { - /* Acknowledge interrupts */ - status = via_read(dev_priv, VIA_REG_INTERRUPT); - via_write(dev_priv, VIA_REG_INTERRUPT, status | - dev_priv->irq_pending_mask); - } -} - -int via_enable_vblank(struct drm_device *dev, unsigned int pipe) -{ - drm_via_private_t *dev_priv = dev->dev_private; - u32 status; - - if (pipe != 0) { - DRM_ERROR("%s: bad crtc %u\n", __func__, pipe); - return -EINVAL; - } - - status = via_read(dev_priv, VIA_REG_INTERRUPT); - via_write(dev_priv, VIA_REG_INTERRUPT, status | VIA_IRQ_VBLANK_ENABLE); - - via_write8(dev_priv, 0x83d4, 0x11); - via_write8_mask(dev_priv, 0x83d5, 0x30, 0x30); - - return 0; -} - -void via_disable_vblank(struct drm_device *dev, unsigned int pipe) -{ - drm_via_private_t *dev_priv = dev->dev_private; - u32 status; - - status = via_read(dev_priv, VIA_REG_INTERRUPT); - via_write(dev_priv, VIA_REG_INTERRUPT, status & ~VIA_IRQ_VBLANK_ENABLE); - - via_write8(dev_priv, 0x83d4, 0x11); - via_write8_mask(dev_priv, 0x83d5, 0x30, 0); - - if (pipe != 0) - DRM_ERROR("%s: bad crtc %u\n", __func__, pipe); -} - -static int -via_driver_irq_wait(struct drm_device *dev, unsigned int irq, int force_sequence, - unsigned int *sequence) -{ - drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; - unsigned int cur_irq_sequence; - drm_via_irq_t *cur_irq; - int ret = 0; - maskarray_t *masks; - int real_irq; - - DRM_DEBUG("\n"); - - if (!dev_priv) { - DRM_ERROR("called with no initialization\n"); - return -EINVAL; - } - - if (irq >= drm_via_irq_num) { - DRM_ERROR("Trying to wait on unknown irq %d\n", irq); - return -EINVAL; - } - - real_irq = dev_priv->irq_map[irq]; - - if (real_irq < 0) { - DRM_ERROR("Video IRQ %d not available on this hardware.\n", - irq); - return -EINVAL; - } - - masks = dev_priv->irq_masks; - cur_irq = dev_priv->via_irqs + real_irq; - - if (masks[real_irq][2] && !force_sequence) { - VIA_WAIT_ON(ret, cur_irq->irq_queue, 3 * HZ, - ((via_read(dev_priv, masks[irq][2]) & masks[irq][3]) == - masks[irq][4])); - cur_irq_sequence = atomic_read(&cur_irq->irq_received); - } else { - VIA_WAIT_ON(ret, cur_irq->irq_queue, 3 * HZ, - (((cur_irq_sequence = - atomic_read(&cur_irq->irq_received)) - - *sequence) <= (1 << 23))); - } - *sequence = cur_irq_sequence; - return ret; -} - - -/* - * drm_dma.h hooks - */ - -void via_driver_irq_preinstall(struct drm_device *dev) -{ - drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; - u32 status; - drm_via_irq_t *cur_irq; - int i; - - DRM_DEBUG("dev_priv: %p\n", dev_priv); - if (dev_priv) { - cur_irq = dev_priv->via_irqs; - - dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE; - dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING; - - if (dev_priv->chipset == VIA_PRO_GROUP_A || - dev_priv->chipset == VIA_DX9_0) { - dev_priv->irq_masks = via_pro_group_a_irqs; - dev_priv->num_irqs = via_num_pro_group_a; - dev_priv->irq_map = via_irqmap_pro_group_a; - } else { - dev_priv->irq_masks = via_unichrome_irqs; - dev_priv->num_irqs = via_num_unichrome; - dev_priv->irq_map = via_irqmap_unichrome; - } - - for (i = 0; i < dev_priv->num_irqs; ++i) { - atomic_set(&cur_irq->irq_received, 0); - cur_irq->enable_mask = dev_priv->irq_masks[i][0]; - cur_irq->pending_mask = dev_priv->irq_masks[i][1]; - init_waitqueue_head(&cur_irq->irq_queue); - dev_priv->irq_enable_mask |= cur_irq->enable_mask; - dev_priv->irq_pending_mask |= cur_irq->pending_mask; - cur_irq++; - - DRM_DEBUG("Initializing IRQ %d\n", i); - } - - dev_priv->last_vblank_valid = 0; - - /* Clear VSync interrupt regs */ - status = via_read(dev_priv, VIA_REG_INTERRUPT); - via_write(dev_priv, VIA_REG_INTERRUPT, status & - ~(dev_priv->irq_enable_mask)); - - /* Clear bits if they're already high */ - viadrv_acknowledge_irqs(dev_priv); - } -} - -int via_driver_irq_postinstall(struct drm_device *dev) -{ - drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; - u32 status; - - DRM_DEBUG("fun: %s\n", __func__); - if (!dev_priv) - return -EINVAL; - - status = via_read(dev_priv, VIA_REG_INTERRUPT); - via_write(dev_priv, VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL - | dev_priv->irq_enable_mask); - - /* Some magic, oh for some data sheets ! */ - via_write8(dev_priv, 0x83d4, 0x11); - via_write8_mask(dev_priv, 0x83d5, 0x30, 0x30); - - return 0; -} - -void via_driver_irq_uninstall(struct drm_device *dev) -{ - drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; - u32 status; - - DRM_DEBUG("\n"); - if (dev_priv) { - - /* Some more magic, oh for some data sheets ! */ - - via_write8(dev_priv, 0x83d4, 0x11); - via_write8_mask(dev_priv, 0x83d5, 0x30, 0); - - status = via_read(dev_priv, VIA_REG_INTERRUPT); - via_write(dev_priv, VIA_REG_INTERRUPT, status & - ~(VIA_IRQ_VBLANK_ENABLE | dev_priv->irq_enable_mask)); - } -} - -int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - drm_via_irqwait_t *irqwait = data; - struct timespec64 now; - int ret = 0; - drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; - drm_via_irq_t *cur_irq = dev_priv->via_irqs; - int force_sequence; - - if (irqwait->request.irq >= dev_priv->num_irqs) { - DRM_ERROR("Trying to wait on unknown irq %d\n", - irqwait->request.irq); - return -EINVAL; - } - - cur_irq += irqwait->request.irq; - - switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) { - case VIA_IRQ_RELATIVE: - irqwait->request.sequence += - atomic_read(&cur_irq->irq_received); - irqwait->request.type &= ~_DRM_VBLANK_RELATIVE; - break; - case VIA_IRQ_ABSOLUTE: - break; - default: - return -EINVAL; - } - - if (irqwait->request.type & VIA_IRQ_SIGNAL) { - DRM_ERROR("Signals on Via IRQs not implemented yet.\n"); - return -EINVAL; - } - - force_sequence = (irqwait->request.type & VIA_IRQ_FORCE_SEQUENCE); - - ret = via_driver_irq_wait(dev, irqwait->request.irq, force_sequence, - &irqwait->request.sequence); - ktime_get_ts64(&now); - irqwait->reply.tval_sec = now.tv_sec; - irqwait->reply.tval_usec = now.tv_nsec / NSEC_PER_USEC; - - return ret; -} diff --git a/drivers/gpu/drm/via/via_map.c b/drivers/gpu/drm/via/via_map.c deleted file mode 100644 index a9f6b0c11966..000000000000 --- a/drivers/gpu/drm/via/via_map.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. - * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sub license, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include <linux/pci.h> - -#include <drm/drm_device.h> -#include <drm/drm_vblank.h> -#include <drm/via_drm.h> - -#include "via_drv.h" - -static int via_do_init_map(struct drm_device *dev, drm_via_init_t *init) -{ - drm_via_private_t *dev_priv = dev->dev_private; - - DRM_DEBUG("\n"); - - dev_priv->sarea = drm_legacy_getsarea(dev); - if (!dev_priv->sarea) { - DRM_ERROR("could not find sarea!\n"); - dev->dev_private = (void *)dev_priv; - via_do_cleanup_map(dev); - return -EINVAL; - } - - dev_priv->fb = drm_legacy_findmap(dev, init->fb_offset); - if (!dev_priv->fb) { - DRM_ERROR("could not find framebuffer!\n"); - dev->dev_private = (void *)dev_priv; - via_do_cleanup_map(dev); - return -EINVAL; - } - dev_priv->mmio = drm_legacy_findmap(dev, init->mmio_offset); - if (!dev_priv->mmio) { - DRM_ERROR("could not find mmio region!\n"); - dev->dev_private = (void *)dev_priv; - via_do_cleanup_map(dev); - return -EINVAL; - } - - dev_priv->sarea_priv = - (drm_via_sarea_t *) ((u8 *) dev_priv->sarea->handle + - init->sarea_priv_offset); - - dev_priv->agpAddr = init->agpAddr; - - via_init_futex(dev_priv); - - via_init_dmablit(dev); - - dev->dev_private = (void *)dev_priv; - return 0; -} - -int via_do_cleanup_map(struct drm_device *dev) -{ - via_dma_cleanup(dev); - - return 0; -} - -int via_map_init(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - drm_via_init_t *init = data; - - DRM_DEBUG("\n"); - - switch (init->func) { - case VIA_INIT_MAP: - return via_do_init_map(dev, init); - case VIA_CLEANUP_MAP: - return via_do_cleanup_map(dev); - } - - return -EINVAL; -} - -int via_driver_load(struct drm_device *dev, unsigned long chipset) -{ - struct pci_dev *pdev = to_pci_dev(dev->dev); - drm_via_private_t *dev_priv; - int ret = 0; - - dev_priv = kzalloc(sizeof(drm_via_private_t), GFP_KERNEL); - if (dev_priv == NULL) - return -ENOMEM; - - idr_init(&dev_priv->object_idr); - dev->dev_private = (void *)dev_priv; - - dev_priv->chipset = chipset; - - pci_set_master(pdev); - - ret = drm_vblank_init(dev, 1); - if (ret) { - kfree(dev_priv); - return ret; - } - - return 0; -} - -void via_driver_unload(struct drm_device *dev) -{ - drm_via_private_t *dev_priv = dev->dev_private; - - idr_destroy(&dev_priv->object_idr); - - kfree(dev_priv); -} diff --git a/drivers/gpu/drm/via/via_mm.c b/drivers/gpu/drm/via/via_mm.c deleted file mode 100644 index c9afa1a51f23..000000000000 --- a/drivers/gpu/drm/via/via_mm.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright 2006 Tungsten Graphics Inc., Bismarck, ND., USA. - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sub license, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ -/* - * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com> - */ - -#include <linux/slab.h> - -#include <drm/drm_device.h> -#include <drm/drm_file.h> -#include <drm/via_drm.h> - -#include "via_drv.h" - -#define VIA_MM_ALIGN_SHIFT 4 -#define VIA_MM_ALIGN_MASK ((1 << VIA_MM_ALIGN_SHIFT) - 1) - -struct via_memblock { - struct drm_mm_node mm_node; - struct list_head owner_list; -}; - -int via_agp_init(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - drm_via_agp_t *agp = data; - drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; - - mutex_lock(&dev->struct_mutex); - drm_mm_init(&dev_priv->agp_mm, 0, agp->size >> VIA_MM_ALIGN_SHIFT); - - dev_priv->agp_initialized = 1; - dev_priv->agp_offset = agp->offset; - mutex_unlock(&dev->struct_mutex); - - DRM_DEBUG("offset = %u, size = %u\n", agp->offset, agp->size); - return 0; -} - -int via_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - drm_via_fb_t *fb = data; - drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; - - mutex_lock(&dev->struct_mutex); - drm_mm_init(&dev_priv->vram_mm, 0, fb->size >> VIA_MM_ALIGN_SHIFT); - - dev_priv->vram_initialized = 1; - dev_priv->vram_offset = fb->offset; - - mutex_unlock(&dev->struct_mutex); - DRM_DEBUG("offset = %u, size = %u\n", fb->offset, fb->size); - - return 0; - -} - -int via_final_context(struct drm_device *dev, int context) -{ - drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; - - via_release_futex(dev_priv, context); - - /* Linux specific until context tracking code gets ported to BSD */ - /* Last context, perform cleanup */ - if (list_is_singular(&dev->ctxlist)) { - DRM_DEBUG("Last Context\n"); - drm_legacy_irq_uninstall(dev); - via_cleanup_futex(dev_priv); - via_do_cleanup_map(dev); - } - return 1; -} - -void via_lastclose(struct drm_device *dev) -{ - drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; - - if (!dev_priv) - return; - - mutex_lock(&dev->struct_mutex); - if (dev_priv->vram_initialized) { - drm_mm_takedown(&dev_priv->vram_mm); - dev_priv->vram_initialized = 0; - } - if (dev_priv->agp_initialized) { - drm_mm_takedown(&dev_priv->agp_mm); - dev_priv->agp_initialized = 0; - } - mutex_unlock(&dev->struct_mutex); -} - -int via_mem_alloc(struct drm_device *dev, void *data, - struct drm_file *file) -{ - drm_via_mem_t *mem = data; - int retval = 0, user_key; - struct via_memblock *item; - drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; - struct via_file_private *file_priv = file->driver_priv; - unsigned long tmpSize; - - if (mem->type > VIA_MEM_AGP) { - DRM_ERROR("Unknown memory type allocation\n"); - return -EINVAL; - } - mutex_lock(&dev->struct_mutex); - if (0 == ((mem->type == VIA_MEM_VIDEO) ? dev_priv->vram_initialized : - dev_priv->agp_initialized)) { - mutex_unlock(&dev->struct_mutex); - DRM_ERROR - ("Attempt to allocate from uninitialized memory manager.\n"); - return -EINVAL; - } - - item = kzalloc(sizeof(*item), GFP_KERNEL); - if (!item) { - retval = -ENOMEM; - goto fail_alloc; - } - - tmpSize = (mem->size + VIA_MM_ALIGN_MASK) >> VIA_MM_ALIGN_SHIFT; - if (mem->type == VIA_MEM_AGP) - retval = drm_mm_insert_node(&dev_priv->agp_mm, - &item->mm_node, - tmpSize); - else - retval = drm_mm_insert_node(&dev_priv->vram_mm, - &item->mm_node, - tmpSize); - if (retval) - goto fail_alloc; - - retval = idr_alloc(&dev_priv->object_idr, item, 1, 0, GFP_KERNEL); - if (retval < 0) - goto fail_idr; - user_key = retval; - - list_add(&item->owner_list, &file_priv->obj_list); - mutex_unlock(&dev->struct_mutex); - - mem->offset = ((mem->type == VIA_MEM_VIDEO) ? - dev_priv->vram_offset : dev_priv->agp_offset) + - ((item->mm_node.start) << VIA_MM_ALIGN_SHIFT); - mem->index = user_key; - - return 0; - -fail_idr: - drm_mm_remove_node(&item->mm_node); -fail_alloc: - kfree(item); - mutex_unlock(&dev->struct_mutex); - - mem->offset = 0; - mem->size = 0; - mem->index = 0; - DRM_DEBUG("Video memory allocation failed\n"); - - return retval; -} - -int via_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - drm_via_private_t *dev_priv = dev->dev_private; - drm_via_mem_t *mem = data; - struct via_memblock *obj; - - mutex_lock(&dev->struct_mutex); - obj = idr_find(&dev_priv->object_idr, mem->index); - if (obj == NULL) { - mutex_unlock(&dev->struct_mutex); - return -EINVAL; - } - - idr_remove(&dev_priv->object_idr, mem->index); - list_del(&obj->owner_list); - drm_mm_remove_node(&obj->mm_node); - kfree(obj); - mutex_unlock(&dev->struct_mutex); - - DRM_DEBUG("free = 0x%lx\n", mem->index); - - return 0; -} - - -void via_reclaim_buffers_locked(struct drm_device *dev, - struct drm_file *file) -{ - struct via_file_private *file_priv = file->driver_priv; - struct via_memblock *entry, *next; - - if (!(dev->master && file->master->lock.hw_lock)) - return; - - drm_legacy_idlelock_take(&file->master->lock); - - mutex_lock(&dev->struct_mutex); - if (list_empty(&file_priv->obj_list)) { - mutex_unlock(&dev->struct_mutex); - drm_legacy_idlelock_release(&file->master->lock); - - return; - } - - via_driver_dma_quiescent(dev); - - list_for_each_entry_safe(entry, next, &file_priv->obj_list, - owner_list) { - list_del(&entry->owner_list); - drm_mm_remove_node(&entry->mm_node); - kfree(entry); - } - mutex_unlock(&dev->struct_mutex); - - drm_legacy_idlelock_release(&file->master->lock); - - return; -} diff --git a/drivers/gpu/drm/via/via_verifier.c b/drivers/gpu/drm/via/via_verifier.c deleted file mode 100644 index 3d6e3a70f318..000000000000 --- a/drivers/gpu/drm/via/via_verifier.c +++ /dev/null @@ -1,1110 +0,0 @@ -/* - * Copyright 2004 The Unichrome Project. All Rights Reserved. - * Copyright 2005 Thomas Hellstrom. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sub license, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE AUTHOR(S), AND/OR THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Author: Thomas Hellstrom 2004, 2005. - * This code was written using docs obtained under NDA from VIA Inc. - * - * Don't run this code directly on an AGP buffer. Due to cache problems it will - * be very slow. - */ - -#include <drm/drm_device.h> -#include <drm/drm_legacy.h> -#include <drm/via_drm.h> - -#include "via_3d_reg.h" -#include "via_drv.h" -#include "via_verifier.h" - -typedef enum { - state_command, - state_header2, - state_header1, - state_vheader5, - state_vheader6, - state_error -} verifier_state_t; - -typedef enum { - no_check = 0, - check_for_header2, - check_for_header1, - check_for_header2_err, - check_for_header1_err, - check_for_fire, - check_z_buffer_addr0, - check_z_buffer_addr1, - check_z_buffer_addr_mode, - check_destination_addr0, - check_destination_addr1, - check_destination_addr_mode, - check_for_dummy, - check_for_dd, - check_texture_addr0, - check_texture_addr1, - check_texture_addr2, - check_texture_addr3, - check_texture_addr4, - check_texture_addr5, - check_texture_addr6, - check_texture_addr7, - check_texture_addr8, - check_texture_addr_mode, - check_for_vertex_count, - check_number_texunits, - forbidden_command -} hazard_t; - -/* - * Associates each hazard above with a possible multi-command - * sequence. For example an address that is split over multiple - * commands and that needs to be checked at the first command - * that does not include any part of the address. - */ - -static drm_via_sequence_t seqs[] = { - no_sequence, - no_sequence, - no_sequence, - no_sequence, - no_sequence, - no_sequence, - z_address, - z_address, - z_address, - dest_address, - dest_address, - dest_address, - no_sequence, - no_sequence, - tex_address, - tex_address, - tex_address, - tex_address, - tex_address, - tex_address, - tex_address, - tex_address, - tex_address, - tex_address, - no_sequence -}; - -typedef struct { - unsigned int code; - hazard_t hz; -} hz_init_t; - -static hz_init_t init_table1[] = { - {0xf2, check_for_header2_err}, - {0xf0, check_for_header1_err}, - {0xee, check_for_fire}, - {0xcc, check_for_dummy}, - {0xdd, check_for_dd}, - {0x00, no_check}, - {0x10, check_z_buffer_addr0}, - {0x11, check_z_buffer_addr1}, - {0x12, check_z_buffer_addr_mode}, - {0x13, no_check}, - {0x14, no_check}, - {0x15, no_check}, - {0x23, no_check}, - {0x24, no_check}, - {0x33, no_check}, - {0x34, no_check}, - {0x35, no_check}, - {0x36, no_check}, - {0x37, no_check}, - {0x38, no_check}, - {0x39, no_check}, - {0x3A, no_check}, - {0x3B, no_check}, - {0x3C, no_check}, - {0x3D, no_check}, - {0x3E, no_check}, - {0x40, check_destination_addr0}, - {0x41, check_destination_addr1}, - {0x42, check_destination_addr_mode}, - {0x43, no_check}, - {0x44, no_check}, - {0x50, no_check}, - {0x51, no_check}, - {0x52, no_check}, - {0x53, no_check}, - {0x54, no_check}, - {0x55, no_check}, - {0x56, no_check}, - {0x57, no_check}, - {0x58, no_check}, - {0x70, no_check}, - {0x71, no_check}, - {0x78, no_check}, - {0x79, no_check}, - {0x7A, no_check}, - {0x7B, no_check}, - {0x7C, no_check}, - {0x7D, check_for_vertex_count} -}; - -static hz_init_t init_table2[] = { - {0xf2, check_for_header2_err}, - {0xf0, check_for_header1_err}, - {0xee, check_for_fire}, - {0xcc, check_for_dummy}, - {0x00, check_texture_addr0}, - {0x01, check_texture_addr0}, - {0x02, check_texture_addr0}, - {0x03, check_texture_addr0}, - {0x04, check_texture_addr0}, - {0x05, check_texture_addr0}, - {0x06, check_texture_addr0}, - {0x07, check_texture_addr0}, - {0x08, check_texture_addr0}, - {0x09, check_texture_addr0}, - {0x20, check_texture_addr1}, - {0x21, check_texture_addr1}, - {0x22, check_texture_addr1}, - {0x23, check_texture_addr4}, - {0x2B, check_texture_addr3}, - {0x2C, check_texture_addr3}, - {0x2D, check_texture_addr3}, - {0x2E, check_texture_addr3}, - {0x2F, check_texture_addr3}, - {0x30, check_texture_addr3}, - {0x31, check_texture_addr3}, - {0x32, check_texture_addr3}, - {0x33, check_texture_addr3}, - {0x34, check_texture_addr3}, - {0x4B, check_texture_addr5}, - {0x4C, check_texture_addr6}, - {0x51, check_texture_addr7}, - {0x52, check_texture_addr8}, - {0x77, check_texture_addr2}, - {0x78, no_check}, - {0x79, no_check}, - {0x7A, no_check}, - {0x7B, check_texture_addr_mode}, - {0x7C, no_check}, - {0x7D, no_check}, - {0x7E, no_check}, - {0x7F, no_check}, - {0x80, no_check}, - {0x81, no_check}, - {0x82, no_check}, - {0x83, no_check}, - {0x85, no_check}, - {0x86, no_check}, - {0x87, no_check}, - {0x88, no_check}, - {0x89, no_check}, - {0x8A, no_check}, - {0x90, no_check}, - {0x91, no_check}, - {0x92, no_check}, - {0x93, no_check} -}; - -static hz_init_t init_table3[] = { - {0xf2, check_for_header2_err}, - {0xf0, check_for_header1_err}, - {0xcc, check_for_dummy}, - {0x00, check_number_texunits} -}; - -static hazard_t table1[256]; -static hazard_t table2[256]; -static hazard_t table3[256]; - -static __inline__ int -eat_words(const uint32_t **buf, const uint32_t *buf_end, unsigned num_words) -{ - if ((buf_end - *buf) >= num_words) { - *buf += num_words; - return 0; - } - DRM_ERROR("Illegal termination of DMA command buffer\n"); - return 1; -} - -/* - * Partially stolen from drm_memory.h - */ - -static __inline__ drm_local_map_t *via_drm_lookup_agp_map(drm_via_state_t *seq, - unsigned long offset, - unsigned long size, - struct drm_device *dev) -{ - struct drm_map_list *r_list; - drm_local_map_t *map = seq->map_cache; - - if (map && map->offset <= offset - && (offset + size) <= (map->offset + map->size)) { - return map; - } - - list_for_each_entry(r_list, &dev->maplist, head) { - map = r_list->map; - if (!map) - continue; - if (map->offset <= offset - && (offset + size) <= (map->offset + map->size) - && !(map->flags & _DRM_RESTRICTED) - && (map->type == _DRM_AGP)) { - seq->map_cache = map; - return map; - } - } - return NULL; -} - -/* - * Require that all AGP texture levels reside in the same AGP map which should - * be mappable by the client. This is not a big restriction. - * FIXME: To actually enforce this security policy strictly, drm_rmmap - * would have to wait for dma quiescent before removing an AGP map. - * The via_drm_lookup_agp_map call in reality seems to take - * very little CPU time. - */ - -static __inline__ int finish_current_sequence(drm_via_state_t * cur_seq) -{ - switch (cur_seq->unfinished) { - case z_address: - DRM_DEBUG("Z Buffer start address is 0x%x\n", cur_seq->z_addr); - break; - case dest_address: - DRM_DEBUG("Destination start address is 0x%x\n", - cur_seq->d_addr); - break; - case tex_address: - if (cur_seq->agp_texture) { - unsigned start = - cur_seq->tex_level_lo[cur_seq->texture]; - unsigned end = cur_seq->tex_level_hi[cur_seq->texture]; - unsigned long lo = ~0, hi = 0, tmp; - uint32_t *addr, *pitch, *height, tex; - unsigned i; - int npot; - - if (end > 9) - end = 9; - if (start > 9) - start = 9; - - addr = - &(cur_seq->t_addr[tex = cur_seq->texture][start]); - pitch = &(cur_seq->pitch[tex][start]); - height = &(cur_seq->height[tex][start]); - npot = cur_seq->tex_npot[tex]; - for (i = start; i <= end; ++i) { - tmp = *addr++; - if (tmp < lo) - lo = tmp; - if (i == 0 && npot) - tmp += (*height++ * *pitch++); - else - tmp += (*height++ << *pitch++); - if (tmp > hi) - hi = tmp; - } - - if (!via_drm_lookup_agp_map - (cur_seq, lo, hi - lo, cur_seq->dev)) { - DRM_ERROR - ("AGP texture is not in allowed map\n"); - return 2; - } - } - break; - default: - break; - } - cur_seq->unfinished = no_sequence; - return 0; -} - -static __inline__ int -investigate_hazard(uint32_t cmd, hazard_t hz, drm_via_state_t *cur_seq) -{ - register uint32_t tmp, *tmp_addr; - - if (cur_seq->unfinished && (cur_seq->unfinished != seqs[hz])) { - int ret; - if ((ret = finish_current_sequence(cur_seq))) - return ret; - } - - switch (hz) { - case check_for_header2: - if (cmd == HALCYON_HEADER2) - return 1; - return 0; - case check_for_header1: - if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) - return 1; - return 0; - case check_for_header2_err: - if (cmd == HALCYON_HEADER2) - return 1; - DRM_ERROR("Illegal DMA HALCYON_HEADER2 command\n"); - break; - case check_for_header1_err: - if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) - return 1; - DRM_ERROR("Illegal DMA HALCYON_HEADER1 command\n"); - break; - case check_for_fire: - if ((cmd & HALCYON_FIREMASK) == HALCYON_FIRECMD) - return 1; - DRM_ERROR("Illegal DMA HALCYON_FIRECMD command\n"); - break; - case check_for_dummy: - if (HC_DUMMY == cmd) - return 0; - DRM_ERROR("Illegal DMA HC_DUMMY command\n"); - break; - case check_for_dd: - if (0xdddddddd == cmd) - return 0; - DRM_ERROR("Illegal DMA 0xdddddddd command\n"); - break; - case check_z_buffer_addr0: - cur_seq->unfinished = z_address; - cur_seq->z_addr = (cur_seq->z_addr & 0xFF000000) | - (cmd & 0x00FFFFFF); - return 0; - case check_z_buffer_addr1: - cur_seq->unfinished = z_address; - cur_seq->z_addr = (cur_seq->z_addr & 0x00FFFFFF) | - ((cmd & 0xFF) << 24); - return 0; - case check_z_buffer_addr_mode: - cur_seq->unfinished = z_address; - if ((cmd & 0x0000C000) == 0) - return 0; - DRM_ERROR("Attempt to place Z buffer in system memory\n"); - return 2; - case check_destination_addr0: - cur_seq->unfinished = dest_address; - cur_seq->d_addr = (cur_seq->d_addr & 0xFF000000) | - (cmd & 0x00FFFFFF); - return 0; - case check_destination_addr1: - cur_seq->unfinished = dest_address; - cur_seq->d_addr = (cur_seq->d_addr & 0x00FFFFFF) | - ((cmd & 0xFF) << 24); - return 0; - case check_destination_addr_mode: - cur_seq->unfinished = dest_address; - if ((cmd & 0x0000C000) == 0) - return 0; - DRM_ERROR - ("Attempt to place 3D drawing buffer in system memory\n"); - return 2; - case check_texture_addr0: - cur_seq->unfinished = tex_address; - tmp = (cmd >> 24); - tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp]; - *tmp_addr = (*tmp_addr & 0xFF000000) | (cmd & 0x00FFFFFF); - return 0; - case check_texture_addr1: - cur_seq->unfinished = tex_address; - tmp = ((cmd >> 24) - 0x20); - tmp += tmp << 1; - tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp]; - *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24); - tmp_addr++; - *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF00) << 16); - tmp_addr++; - *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF0000) << 8); - return 0; - case check_texture_addr2: - cur_seq->unfinished = tex_address; - cur_seq->tex_level_lo[tmp = cur_seq->texture] = cmd & 0x3F; - cur_seq->tex_level_hi[tmp] = (cmd & 0xFC0) >> 6; - return 0; - case check_texture_addr3: - cur_seq->unfinished = tex_address; - tmp = ((cmd >> 24) - HC_SubA_HTXnL0Pit); - if (tmp == 0 && - (cmd & HC_HTXnEnPit_MASK)) { - cur_seq->pitch[cur_seq->texture][tmp] = - (cmd & HC_HTXnLnPit_MASK); - cur_seq->tex_npot[cur_seq->texture] = 1; - } else { - cur_seq->pitch[cur_seq->texture][tmp] = - (cmd & HC_HTXnLnPitE_MASK) >> HC_HTXnLnPitE_SHIFT; - cur_seq->tex_npot[cur_seq->texture] = 0; - if (cmd & 0x000FFFFF) { - DRM_ERROR - ("Unimplemented texture level 0 pitch mode.\n"); - return 2; - } - } - return 0; - case check_texture_addr4: - cur_seq->unfinished = tex_address; - tmp_addr = &cur_seq->t_addr[cur_seq->texture][9]; - *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24); - return 0; - case check_texture_addr5: - case check_texture_addr6: - cur_seq->unfinished = tex_address; - /* - * Texture width. We don't care since we have the pitch. - */ - return 0; - case check_texture_addr7: - cur_seq->unfinished = tex_address; - tmp_addr = &(cur_seq->height[cur_seq->texture][0]); - tmp_addr[5] = 1 << ((cmd & 0x00F00000) >> 20); - tmp_addr[4] = 1 << ((cmd & 0x000F0000) >> 16); - tmp_addr[3] = 1 << ((cmd & 0x0000F000) >> 12); - tmp_addr[2] = 1 << ((cmd & 0x00000F00) >> 8); - tmp_addr[1] = 1 << ((cmd & 0x000000F0) >> 4); - tmp_addr[0] = 1 << (cmd & 0x0000000F); - return 0; - case check_texture_addr8: - cur_seq->unfinished = tex_address; - tmp_addr = &(cur_seq->height[cur_seq->texture][0]); - tmp_addr[9] = 1 << ((cmd & 0x0000F000) >> 12); - tmp_addr[8] = 1 << ((cmd & 0x00000F00) >> 8); - tmp_addr[7] = 1 << ((cmd & 0x000000F0) >> 4); - tmp_addr[6] = 1 << (cmd & 0x0000000F); - return 0; - case check_texture_addr_mode: - cur_seq->unfinished = tex_address; - if (2 == (tmp = cmd & 0x00000003)) { - DRM_ERROR - ("Attempt to fetch texture from system memory.\n"); - return 2; - } - cur_seq->agp_texture = (tmp == 3); - cur_seq->tex_palette_size[cur_seq->texture] = - (cmd >> 16) & 0x000000007; - return 0; - case check_for_vertex_count: - cur_seq->vertex_count = cmd & 0x0000FFFF; - return 0; - case check_number_texunits: - cur_seq->multitex = (cmd >> 3) & 1; - return 0; - default: - DRM_ERROR("Illegal DMA data: 0x%x\n", cmd); - return 2; - } - return 2; -} - -static __inline__ int -via_check_prim_list(uint32_t const **buffer, const uint32_t * buf_end, - drm_via_state_t *cur_seq) -{ - drm_via_private_t *dev_priv = - (drm_via_private_t *) cur_seq->dev->dev_private; - uint32_t a_fire, bcmd, dw_count; - int ret = 0; - int have_fire; - const uint32_t *buf = *buffer; - - while (buf < buf_end) { - have_fire = 0; - if ((buf_end - buf) < 2) { - DRM_ERROR - ("Unexpected termination of primitive list.\n"); - ret = 1; - break; - } - if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdB) - break; - bcmd = *buf++; - if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdA) { - DRM_ERROR("Expected Vertex List A command, got 0x%x\n", - *buf); - ret = 1; - break; - } - a_fire = - *buf++ | HC_HPLEND_MASK | HC_HPMValidN_MASK | - HC_HE3Fire_MASK; - - /* - * How many dwords per vertex ? - */ - - if (cur_seq->agp && ((bcmd & (0xF << 11)) == 0)) { - DRM_ERROR("Illegal B command vertex data for AGP.\n"); - ret = 1; - break; - } - - dw_count = 0; - if (bcmd & (1 << 7)) - dw_count += (cur_seq->multitex) ? 2 : 1; - if (bcmd & (1 << 8)) - dw_count += (cur_seq->multitex) ? 2 : 1; - if (bcmd & (1 << 9)) - dw_count++; - if (bcmd & (1 << 10)) - dw_count++; - if (bcmd & (1 << 11)) - dw_count++; - if (bcmd & (1 << 12)) - dw_count++; - if (bcmd & (1 << 13)) - dw_count++; - if (bcmd & (1 << 14)) - dw_count++; - - while (buf < buf_end) { - if (*buf == a_fire) { - if (dev_priv->num_fire_offsets >= - VIA_FIRE_BUF_SIZE) { - DRM_ERROR("Fire offset buffer full.\n"); - ret = 1; - break; - } - dev_priv->fire_offsets[dev_priv-> - num_fire_offsets++] = - buf; - have_fire = 1; - buf++; - if (buf < buf_end && *buf == a_fire) - buf++; - break; - } - if ((*buf == HALCYON_HEADER2) || - ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD)) { - DRM_ERROR("Missing Vertex Fire command, " - "Stray Vertex Fire command or verifier " - "lost sync.\n"); - ret = 1; - break; - } - if ((ret = eat_words(&buf, buf_end, dw_count))) - break; - } - if (buf >= buf_end && !have_fire) { - DRM_ERROR("Missing Vertex Fire command or verifier " - "lost sync.\n"); - ret = 1; - break; - } - if (cur_seq->agp && ((buf - cur_seq->buf_start) & 0x01)) { - DRM_ERROR("AGP Primitive list end misaligned.\n"); - ret = 1; - break; - } - } - *buffer = buf; - return ret; -} - -static __inline__ verifier_state_t -via_check_header2(uint32_t const **buffer, const uint32_t *buf_end, - drm_via_state_t *hc_state) -{ - uint32_t cmd; - int hz_mode; - hazard_t hz; - const uint32_t *buf = *buffer; - const hazard_t *hz_table; - - if ((buf_end - buf) < 2) { - DRM_ERROR - ("Illegal termination of DMA HALCYON_HEADER2 sequence.\n"); - return state_error; - } - buf++; - cmd = (*buf++ & 0xFFFF0000) >> 16; - - switch (cmd) { - case HC_ParaType_CmdVdata: - if (via_check_prim_list(&buf, buf_end, hc_state)) - return state_error; - *buffer = buf; - return state_command; - case HC_ParaType_NotTex: - hz_table = table1; - break; - case HC_ParaType_Tex: - hc_state->texture = 0; - hz_table = table2; - break; - case (HC_ParaType_Tex | (HC_SubType_Tex1 << 8)): - hc_state->texture = 1; - hz_table = table2; - break; - case (HC_ParaType_Tex | (HC_SubType_TexGeneral << 8)): - hz_table = table3; - break; - case HC_ParaType_Auto: - if (eat_words(&buf, buf_end, 2)) - return state_error; - *buffer = buf; - return state_command; - case (HC_ParaType_Palette | (HC_SubType_Stipple << 8)): - if (eat_words(&buf, buf_end, 32)) - return state_error; - *buffer = buf; - return state_command; - case (HC_ParaType_Palette | (HC_SubType_TexPalette0 << 8)): - case (HC_ParaType_Palette | (HC_SubType_TexPalette1 << 8)): - DRM_ERROR("Texture palettes are rejected because of " - "lack of info how to determine their size.\n"); - return state_error; - case (HC_ParaType_Palette | (HC_SubType_FogTable << 8)): - DRM_ERROR("Fog factor palettes are rejected because of " - "lack of info how to determine their size.\n"); - return state_error; - default: - - /* - * There are some unimplemented HC_ParaTypes here, that - * need to be implemented if the Mesa driver is extended. - */ - - DRM_ERROR("Invalid or unimplemented HALCYON_HEADER2 " - "DMA subcommand: 0x%x. Previous dword: 0x%x\n", - cmd, *(buf - 2)); - *buffer = buf; - return state_error; - } - - while (buf < buf_end) { - cmd = *buf++; - if ((hz = hz_table[cmd >> 24])) { - if ((hz_mode = investigate_hazard(cmd, hz, hc_state))) { - if (hz_mode == 1) { - buf--; - break; - } - return state_error; - } - } else if (hc_state->unfinished && - finish_current_sequence(hc_state)) { - return state_error; - } - } - if (hc_state->unfinished && finish_current_sequence(hc_state)) - return state_error; - *buffer = buf; - return state_command; -} - -static __inline__ verifier_state_t -via_parse_header2(drm_via_private_t *dev_priv, uint32_t const **buffer, - const uint32_t *buf_end, int *fire_count) -{ - uint32_t cmd; - const uint32_t *buf = *buffer; - const uint32_t *next_fire; - int burst = 0; - - next_fire = dev_priv->fire_offsets[*fire_count]; - buf++; - cmd = (*buf & 0xFFFF0000) >> 16; - via_write(dev_priv, HC_REG_TRANS_SET + HC_REG_BASE, *buf++); - switch (cmd) { - case HC_ParaType_CmdVdata: - while ((buf < buf_end) && - (*fire_count < dev_priv->num_fire_offsets) && - (*buf & HC_ACMD_MASK) == HC_ACMD_HCmdB) { - while (buf <= next_fire) { - via_write(dev_priv, HC_REG_TRANS_SPACE + HC_REG_BASE + - (burst & 63), *buf++); - burst += 4; - } - if ((buf < buf_end) - && ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD)) - buf++; - - if (++(*fire_count) < dev_priv->num_fire_offsets) - next_fire = dev_priv->fire_offsets[*fire_count]; - } - break; - default: - while (buf < buf_end) { - - if (*buf == HC_HEADER2 || - (*buf & HALCYON_HEADER1MASK) == HALCYON_HEADER1 || - (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5 || - (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6) - break; - - via_write(dev_priv, HC_REG_TRANS_SPACE + HC_REG_BASE + - (burst & 63), *buf++); - burst += 4; - } - } - *buffer = buf; - return state_command; -} - -static __inline__ int verify_mmio_address(uint32_t address) -{ - if ((address > 0x3FF) && (address < 0xC00)) { - DRM_ERROR("Invalid VIDEO DMA command. " - "Attempt to access 3D- or command burst area.\n"); - return 1; - } else if ((address > 0xCFF) && (address < 0x1300)) { - DRM_ERROR("Invalid VIDEO DMA command. " - "Attempt to access PCI DMA area.\n"); - return 1; - } else if (address > 0x13FF) { - DRM_ERROR("Invalid VIDEO DMA command. " - "Attempt to access VGA registers.\n"); - return 1; - } - return 0; -} - -static __inline__ int -verify_video_tail(uint32_t const **buffer, const uint32_t * buf_end, - uint32_t dwords) -{ - const uint32_t *buf = *buffer; - - if (buf_end - buf < dwords) { - DRM_ERROR("Illegal termination of video command.\n"); - return 1; - } - while (dwords--) { - if (*buf++) { - DRM_ERROR("Illegal video command tail.\n"); - return 1; - } - } - *buffer = buf; - return 0; -} - -static __inline__ verifier_state_t -via_check_header1(uint32_t const **buffer, const uint32_t * buf_end) -{ - uint32_t cmd; - const uint32_t *buf = *buffer; - verifier_state_t ret = state_command; - - while (buf < buf_end) { - cmd = *buf; - if ((cmd > ((0x3FF >> 2) | HALCYON_HEADER1)) && - (cmd < ((0xC00 >> 2) | HALCYON_HEADER1))) { - if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) - break; - DRM_ERROR("Invalid HALCYON_HEADER1 command. " - "Attempt to access 3D- or command burst area.\n"); - ret = state_error; - break; - } else if (cmd > ((0xCFF >> 2) | HALCYON_HEADER1)) { - if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) - break; - DRM_ERROR("Invalid HALCYON_HEADER1 command. " - "Attempt to access VGA registers.\n"); - ret = state_error; - break; - } else { - buf += 2; - } - } - *buffer = buf; - return ret; -} - -static __inline__ verifier_state_t -via_parse_header1(drm_via_private_t *dev_priv, uint32_t const **buffer, - const uint32_t *buf_end) -{ - register uint32_t cmd; - const uint32_t *buf = *buffer; - - while (buf < buf_end) { - cmd = *buf; - if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) - break; - via_write(dev_priv, (cmd & ~HALCYON_HEADER1MASK) << 2, *++buf); - buf++; - } - *buffer = buf; - return state_command; -} - -static __inline__ verifier_state_t -via_check_vheader5(uint32_t const **buffer, const uint32_t *buf_end) -{ - uint32_t data; - const uint32_t *buf = *buffer; - - if (buf_end - buf < 4) { - DRM_ERROR("Illegal termination of video header5 command\n"); - return state_error; - } - - data = *buf++ & ~VIA_VIDEOMASK; - if (verify_mmio_address(data)) - return state_error; - - data = *buf++; - if (*buf++ != 0x00F50000) { - DRM_ERROR("Illegal header5 header data\n"); - return state_error; - } - if (*buf++ != 0x00000000) { - DRM_ERROR("Illegal header5 header data\n"); - return state_error; - } - if (eat_words(&buf, buf_end, data)) - return state_error; - if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3))) - return state_error; - *buffer = buf; - return state_command; - -} - -static __inline__ verifier_state_t -via_parse_vheader5(drm_via_private_t *dev_priv, uint32_t const **buffer, - const uint32_t *buf_end) -{ - uint32_t addr, count, i; - const uint32_t *buf = *buffer; - - addr = *buf++ & ~VIA_VIDEOMASK; - i = count = *buf; - buf += 3; - while (i--) - via_write(dev_priv, addr, *buf++); - if (count & 3) - buf += 4 - (count & 3); - *buffer = buf; - return state_command; -} - -static __inline__ verifier_state_t -via_check_vheader6(uint32_t const **buffer, const uint32_t * buf_end) -{ - uint32_t data; - const uint32_t *buf = *buffer; - uint32_t i; - - if (buf_end - buf < 4) { - DRM_ERROR("Illegal termination of video header6 command\n"); - return state_error; - } - buf++; - data = *buf++; - if (*buf++ != 0x00F60000) { - DRM_ERROR("Illegal header6 header data\n"); - return state_error; - } - if (*buf++ != 0x00000000) { - DRM_ERROR("Illegal header6 header data\n"); - return state_error; - } - if ((buf_end - buf) < (data << 1)) { - DRM_ERROR("Illegal termination of video header6 command\n"); - return state_error; - } - for (i = 0; i < data; ++i) { - if (verify_mmio_address(*buf++)) - return state_error; - buf++; - } - data <<= 1; - if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3))) - return state_error; - *buffer = buf; - return state_command; -} - -static __inline__ verifier_state_t -via_parse_vheader6(drm_via_private_t *dev_priv, uint32_t const **buffer, - const uint32_t *buf_end) -{ - - uint32_t addr, count, i; - const uint32_t *buf = *buffer; - - i = count = *++buf; - buf += 3; - while (i--) { - addr = *buf++; - via_write(dev_priv, addr, *buf++); - } - count <<= 1; - if (count & 3) - buf += 4 - (count & 3); - *buffer = buf; - return state_command; -} - -int -via_verify_command_stream(const uint32_t * buf, unsigned int size, - struct drm_device * dev, int agp) -{ - - drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; - drm_via_state_t *hc_state = &dev_priv->hc_state; - drm_via_state_t saved_state = *hc_state; - uint32_t cmd; - const uint32_t *buf_end = buf + (size >> 2); - verifier_state_t state = state_command; - int cme_video; - int supported_3d; - - cme_video = (dev_priv->chipset == VIA_PRO_GROUP_A || - dev_priv->chipset == VIA_DX9_0); - - supported_3d = dev_priv->chipset != VIA_DX9_0; - - hc_state->dev = dev; - hc_state->unfinished = no_sequence; - hc_state->map_cache = NULL; - hc_state->agp = agp; - hc_state->buf_start = buf; - dev_priv->num_fire_offsets = 0; - - while (buf < buf_end) { - - switch (state) { - case state_header2: - state = via_check_header2(&buf, buf_end, hc_state); - break; - case state_header1: - state = via_check_header1(&buf, buf_end); - break; - case state_vheader5: - state = via_check_vheader5(&buf, buf_end); - break; - case state_vheader6: - state = via_check_vheader6(&buf, buf_end); - break; - case state_command: - cmd = *buf; - if ((cmd == HALCYON_HEADER2) && supported_3d) - state = state_header2; - else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) - state = state_header1; - else if (cme_video - && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5) - state = state_vheader5; - else if (cme_video - && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6) - state = state_vheader6; - else if ((cmd == HALCYON_HEADER2) && !supported_3d) { - DRM_ERROR("Accelerated 3D is not supported on this chipset yet.\n"); - state = state_error; - } else { - DRM_ERROR - ("Invalid / Unimplemented DMA HEADER command. 0x%x\n", - cmd); - state = state_error; - } - break; - case state_error: - default: - *hc_state = saved_state; - return -EINVAL; - } - } - if (state == state_error) { - *hc_state = saved_state; - return -EINVAL; - } - return 0; -} - -int -via_parse_command_stream(struct drm_device *dev, const uint32_t *buf, - unsigned int size) -{ - - drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; - uint32_t cmd; - const uint32_t *buf_end = buf + (size >> 2); - verifier_state_t state = state_command; - int fire_count = 0; - - while (buf < buf_end) { - - switch (state) { - case state_header2: - state = - via_parse_header2(dev_priv, &buf, buf_end, - &fire_count); - break; - case state_header1: - state = via_parse_header1(dev_priv, &buf, buf_end); - break; - case state_vheader5: - state = via_parse_vheader5(dev_priv, &buf, buf_end); - break; - case state_vheader6: - state = via_parse_vheader6(dev_priv, &buf, buf_end); - break; - case state_command: - cmd = *buf; - if (cmd == HALCYON_HEADER2) - state = state_header2; - else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) - state = state_header1; - else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5) - state = state_vheader5; - else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6) - state = state_vheader6; - else { - DRM_ERROR - ("Invalid / Unimplemented DMA HEADER command. 0x%x\n", - cmd); - state = state_error; - } - break; - case state_error: - default: - return -EINVAL; - } - } - if (state == state_error) - return -EINVAL; - return 0; -} - -static void -setup_hazard_table(hz_init_t init_table[], hazard_t table[], int size) -{ - int i; - - for (i = 0; i < 256; ++i) - table[i] = forbidden_command; - - for (i = 0; i < size; ++i) - table[init_table[i].code] = init_table[i].hz; -} - -void via_init_command_verifier(void) -{ - setup_hazard_table(init_table1, table1, ARRAY_SIZE(init_table1)); - setup_hazard_table(init_table2, table2, ARRAY_SIZE(init_table2)); - setup_hazard_table(init_table3, table3, ARRAY_SIZE(init_table3)); -} diff --git a/drivers/gpu/drm/via/via_verifier.h b/drivers/gpu/drm/via/via_verifier.h deleted file mode 100644 index 26b6d361ab95..000000000000 --- a/drivers/gpu/drm/via/via_verifier.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2004 The Unichrome Project. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sub license, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE UNICHROME PROJECT, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Author: Thomas Hellström 2004. - */ - -#ifndef _VIA_VERIFIER_H_ -#define _VIA_VERIFIER_H_ - -typedef enum { - no_sequence = 0, - z_address, - dest_address, - tex_address -} drm_via_sequence_t; - -typedef struct { - unsigned texture; - uint32_t z_addr; - uint32_t d_addr; - uint32_t t_addr[2][10]; - uint32_t pitch[2][10]; - uint32_t height[2][10]; - uint32_t tex_level_lo[2]; - uint32_t tex_level_hi[2]; - uint32_t tex_palette_size[2]; - uint32_t tex_npot[2]; - drm_via_sequence_t unfinished; - int agp_texture; - int multitex; - struct drm_device *dev; - drm_local_map_t *map_cache; - uint32_t vertex_count; - int agp; - const uint32_t *buf_start; -} drm_via_state_t; - -extern int via_verify_command_stream(const uint32_t *buf, unsigned int size, - struct drm_device *dev, int agp); -extern int via_parse_command_stream(struct drm_device *dev, const uint32_t *buf, - unsigned int size); - -#endif diff --git a/drivers/gpu/drm/via/via_video.c b/drivers/gpu/drm/via/via_video.c deleted file mode 100644 index 53b1f58f99b4..000000000000 --- a/drivers/gpu/drm/via/via_video.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2005 Thomas Hellstrom. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sub license, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE AUTHOR(S), AND/OR THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Author: Thomas Hellstrom 2005. - * - * Video and XvMC related functions. - */ - -#include <drm/drm_device.h> -#include <drm/via_drm.h> - -#include "via_drv.h" - -void via_init_futex(drm_via_private_t *dev_priv) -{ - unsigned int i; - - DRM_DEBUG("\n"); - - for (i = 0; i < VIA_NR_XVMC_LOCKS; ++i) { - init_waitqueue_head(&(dev_priv->decoder_queue[i])); - XVMCLOCKPTR(dev_priv->sarea_priv, i)->lock = 0; - } -} - -void via_cleanup_futex(drm_via_private_t *dev_priv) -{ -} - -void via_release_futex(drm_via_private_t *dev_priv, int context) -{ - unsigned int i; - volatile int *lock; - - if (!dev_priv->sarea_priv) - return; - - for (i = 0; i < VIA_NR_XVMC_LOCKS; ++i) { - lock = (volatile int *)XVMCLOCKPTR(dev_priv->sarea_priv, i); - if ((_DRM_LOCKING_CONTEXT(*lock) == context)) { - if (_DRM_LOCK_IS_HELD(*lock) - && (*lock & _DRM_LOCK_CONT)) { - wake_up(&(dev_priv->decoder_queue[i])); - } - *lock = 0; - } - } -} - -int via_decoder_futex(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - drm_via_futex_t *fx = data; - volatile int *lock; - drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; - drm_via_sarea_t *sAPriv = dev_priv->sarea_priv; - int ret = 0; - - DRM_DEBUG("\n"); - - if (fx->lock >= VIA_NR_XVMC_LOCKS) - return -EFAULT; - - lock = (volatile int *)XVMCLOCKPTR(sAPriv, fx->lock); - - switch (fx->func) { - case VIA_FUTEX_WAIT: - VIA_WAIT_ON(ret, dev_priv->decoder_queue[fx->lock], - (fx->ms / 10) * (HZ / 100), *lock != fx->val); - return ret; - case VIA_FUTEX_WAKE: - wake_up(&(dev_priv->decoder_queue[fx->lock])); - return 0; - } - return 0; -} diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index 5f25a8d15464..0035affc3e59 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c @@ -46,12 +46,11 @@ static int virtio_gpu_modeset = -1; MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); module_param_named(modeset, virtio_gpu_modeset, int, 0400); -static int virtio_gpu_pci_quirk(struct drm_device *dev, struct virtio_device *vdev) +static int virtio_gpu_pci_quirk(struct drm_device *dev) { - struct pci_dev *pdev = to_pci_dev(vdev->dev.parent); + struct pci_dev *pdev = to_pci_dev(dev->dev); const char *pname = dev_name(&pdev->dev); bool vga = (pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA; - char unique[20]; int ret; DRM_INFO("pci: %s detected at %s\n", @@ -63,39 +62,7 @@ static int virtio_gpu_pci_quirk(struct drm_device *dev, struct virtio_device *vd return ret; } - /* - * Normally the drm_dev_set_unique() call is done by core DRM. - * The following comment covers, why virtio cannot rely on it. - * - * Unlike the other virtual GPU drivers, virtio abstracts the - * underlying bus type by using struct virtio_device. - * - * Hence the dev_is_pci() check, used in core DRM, will fail - * and the unique returned will be the virtio_device "virtio0", - * while a "pci:..." one is required. - * - * A few other ideas were considered: - * - Extend the dev_is_pci() check [in drm_set_busid] to - * consider virtio. - * Seems like a bigger hack than what we have already. - * - * - Point drm_device::dev to the parent of the virtio_device - * Semantic changes: - * * Using the wrong device for i2c, framebuffer_alloc and - * prime import. - * Visual changes: - * * Helpers such as DRM_DEV_ERROR, dev_info, drm_printer, - * will print the wrong information. - * - * We could address the latter issues, by introducing - * drm_device::bus_dev, ... which would be used solely for this. - * - * So for the moment keep things as-is, with a bulky comment - * for the next person who feels like removing this - * drm_dev_set_unique() quirk. - */ - snprintf(unique, sizeof(unique), "pci:%s", pname); - return drm_dev_set_unique(dev, unique); + return 0; } static int virtio_gpu_probe(struct virtio_device *vdev) @@ -109,18 +76,24 @@ static int virtio_gpu_probe(struct virtio_device *vdev) if (virtio_gpu_modeset == 0) return -EINVAL; - dev = drm_dev_alloc(&driver, &vdev->dev); + /* + * The virtio-gpu device is a virtual device that doesn't have DMA + * ops assigned to it, nor DMA mask set and etc. Its parent device + * is actual GPU device we want to use it for the DRM's device in + * order to benefit from using generic DRM APIs. + */ + dev = drm_dev_alloc(&driver, vdev->dev.parent); if (IS_ERR(dev)) return PTR_ERR(dev); vdev->priv = dev; - if (!strcmp(vdev->dev.parent->bus->name, "pci")) { - ret = virtio_gpu_pci_quirk(dev, vdev); + if (dev_is_pci(vdev->dev.parent)) { + ret = virtio_gpu_pci_quirk(dev); if (ret) goto err_free; } - ret = virtio_gpu_init(dev); + ret = virtio_gpu_init(vdev, dev); if (ret) goto err_free; diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index f80664cf98d0..9b98470593b0 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -101,8 +101,6 @@ struct virtio_gpu_object { struct virtio_gpu_object_shmem { struct virtio_gpu_object base; - struct sg_table *pages; - uint32_t mapped; }; struct virtio_gpu_object_vram { @@ -215,7 +213,6 @@ struct virtio_gpu_drv_cap_cache { }; struct virtio_gpu_device { - struct device *dev; struct drm_device *ddev; struct virtio_device *vdev; @@ -283,7 +280,7 @@ extern struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS]; void virtio_gpu_create_context(struct drm_device *dev, struct drm_file *file); /* virtgpu_kms.c */ -int virtio_gpu_init(struct drm_device *dev); +int virtio_gpu_init(struct virtio_device *vdev, struct drm_device *dev); void virtio_gpu_deinit(struct drm_device *dev); void virtio_gpu_release(struct drm_device *dev); int virtio_gpu_driver_open(struct drm_device *dev, struct drm_file *file); diff --git a/drivers/gpu/drm/virtio/virtgpu_gem.c b/drivers/gpu/drm/virtio/virtgpu_gem.c index 580a78809836..7db48d17ee3a 100644 --- a/drivers/gpu/drm/virtio/virtgpu_gem.c +++ b/drivers/gpu/drm/virtio/virtgpu_gem.c @@ -228,8 +228,10 @@ int virtio_gpu_array_lock_resv(struct virtio_gpu_object_array *objs) for (i = 0; i < objs->nents; ++i) { ret = dma_resv_reserve_fences(objs->objs[i]->resv, 1); - if (ret) + if (ret) { + virtio_gpu_array_unlock_resv(objs); return ret; + } } return ret; } diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c index 3313b92db531..27b7f14dae89 100644 --- a/drivers/gpu/drm/virtio/virtgpu_kms.c +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c @@ -28,6 +28,7 @@ #include <linux/virtio_ring.h> #include <drm/drm_file.h> +#include <drm/drm_managed.h> #include "virtgpu_drv.h" @@ -66,10 +67,11 @@ static void virtio_gpu_get_capsets(struct virtio_gpu_device *vgdev, { int i, ret; bool invalid_capset_id = false; + struct drm_device *drm = vgdev->ddev; - vgdev->capsets = kcalloc(num_capsets, - sizeof(struct virtio_gpu_drv_capset), - GFP_KERNEL); + vgdev->capsets = drmm_kcalloc(drm, num_capsets, + sizeof(struct virtio_gpu_drv_capset), + GFP_KERNEL); if (!vgdev->capsets) { DRM_ERROR("failed to allocate cap sets\n"); return; @@ -94,7 +96,7 @@ static void virtio_gpu_get_capsets(struct virtio_gpu_device *vgdev, if (ret == 0 || invalid_capset_id) { spin_lock(&vgdev->display_info_lock); - kfree(vgdev->capsets); + drmm_kfree(drm, vgdev->capsets); vgdev->capsets = NULL; spin_unlock(&vgdev->display_info_lock); return; @@ -110,7 +112,7 @@ static void virtio_gpu_get_capsets(struct virtio_gpu_device *vgdev, vgdev->num_capsets = num_capsets; } -int virtio_gpu_init(struct drm_device *dev) +int virtio_gpu_init(struct virtio_device *vdev, struct drm_device *dev) { static vq_callback_t *callbacks[] = { virtio_gpu_ctrl_ack, virtio_gpu_cursor_ack @@ -123,17 +125,16 @@ int virtio_gpu_init(struct drm_device *dev) u32 num_scanouts, num_capsets; int ret = 0; - if (!virtio_has_feature(dev_to_virtio(dev->dev), VIRTIO_F_VERSION_1)) + if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) return -ENODEV; - vgdev = kzalloc(sizeof(struct virtio_gpu_device), GFP_KERNEL); + vgdev = drmm_kzalloc(dev, sizeof(struct virtio_gpu_device), GFP_KERNEL); if (!vgdev) return -ENOMEM; vgdev->ddev = dev; dev->dev_private = vgdev; - vgdev->vdev = dev_to_virtio(dev->dev); - vgdev->dev = dev->dev; + vgdev->vdev = vdev; spin_lock_init(&vgdev->display_info_lock); spin_lock_init(&vgdev->resource_export_lock); @@ -257,7 +258,6 @@ err_vbufs: vgdev->vdev->config->del_vqs(vgdev->vdev); err_vqs: dev->dev_private = NULL; - kfree(vgdev); return ret; } @@ -296,9 +296,6 @@ void virtio_gpu_release(struct drm_device *dev) if (vgdev->has_host_visible) drm_mm_takedown(&vgdev->host_visible_mm); - - kfree(vgdev->capsets); - kfree(vgdev); } int virtio_gpu_driver_open(struct drm_device *dev, struct drm_file *file) diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c index 1cc8f3fc8e4b..8d7728181de0 100644 --- a/drivers/gpu/drm/virtio/virtgpu_object.c +++ b/drivers/gpu/drm/virtio/virtgpu_object.c @@ -67,21 +67,6 @@ void virtio_gpu_cleanup_object(struct virtio_gpu_object *bo) virtio_gpu_resource_id_put(vgdev, bo->hw_res_handle); if (virtio_gpu_is_shmem(bo)) { - struct virtio_gpu_object_shmem *shmem = to_virtio_gpu_shmem(bo); - - if (shmem->pages) { - if (shmem->mapped) { - dma_unmap_sgtable(vgdev->vdev->dev.parent, - shmem->pages, DMA_TO_DEVICE, 0); - shmem->mapped = 0; - } - - sg_free_table(shmem->pages); - kfree(shmem->pages); - shmem->pages = NULL; - drm_gem_shmem_unpin(&bo->base); - } - drm_gem_shmem_free(&bo->base); } else if (virtio_gpu_is_vram(bo)) { struct virtio_gpu_object_vram *vram = to_virtio_gpu_vram(bo); @@ -153,35 +138,18 @@ static int virtio_gpu_object_shmem_init(struct virtio_gpu_device *vgdev, unsigned int *nents) { bool use_dma_api = !virtio_has_dma_quirk(vgdev->vdev); - struct virtio_gpu_object_shmem *shmem = to_virtio_gpu_shmem(bo); struct scatterlist *sg; - int si, ret; + struct sg_table *pages; + int si; - ret = drm_gem_shmem_pin(&bo->base); - if (ret < 0) - return -EINVAL; - - /* - * virtio_gpu uses drm_gem_shmem_get_sg_table instead of - * drm_gem_shmem_get_pages_sgt because virtio has it's own set of - * dma-ops. This is discouraged for other drivers, but should be fine - * since virtio_gpu doesn't support dma-buf import from other devices. - */ - shmem->pages = drm_gem_shmem_get_sg_table(&bo->base); - if (IS_ERR(shmem->pages)) { - drm_gem_shmem_unpin(&bo->base); - return PTR_ERR(shmem->pages); - } + pages = drm_gem_shmem_get_pages_sgt(&bo->base); + if (IS_ERR(pages)) + return PTR_ERR(pages); - if (use_dma_api) { - ret = dma_map_sgtable(vgdev->vdev->dev.parent, - shmem->pages, DMA_TO_DEVICE, 0); - if (ret) - return ret; - *nents = shmem->mapped = shmem->pages->nents; - } else { - *nents = shmem->pages->orig_nents; - } + if (use_dma_api) + *nents = pages->nents; + else + *nents = pages->orig_nents; *ents = kvmalloc_array(*nents, sizeof(struct virtio_gpu_mem_entry), @@ -192,13 +160,13 @@ static int virtio_gpu_object_shmem_init(struct virtio_gpu_device *vgdev, } if (use_dma_api) { - for_each_sgtable_dma_sg(shmem->pages, sg, si) { + for_each_sgtable_dma_sg(pages, sg, si) { (*ents)[si].addr = cpu_to_le64(sg_dma_address(sg)); (*ents)[si].length = cpu_to_le32(sg_dma_len(sg)); (*ents)[si].padding = 0; } } else { - for_each_sgtable_sg(shmem->pages, sg, si) { + for_each_sgtable_sg(pages, sg, si) { (*ents)[si].addr = cpu_to_le64(sg_phys(sg)); (*ents)[si].length = cpu_to_le32(sg->length); (*ents)[si].padding = 0; @@ -234,6 +202,10 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev, bo->dumb = params->dumb; + ret = virtio_gpu_object_shmem_init(vgdev, bo, &ents, &nents); + if (ret != 0) + goto err_put_id; + if (fence) { ret = -ENOMEM; objs = virtio_gpu_array_alloc(1); @@ -246,13 +218,6 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev, goto err_put_objs; } - ret = virtio_gpu_object_shmem_init(vgdev, bo, &ents, &nents); - if (ret != 0) { - virtio_gpu_array_put_free(objs); - virtio_gpu_free_object(&shmem_obj->base); - return ret; - } - if (params->blob) { if (params->blob_mem == VIRTGPU_BLOB_MEM_GUEST) bo->guest_blob = true; diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c index 6d3cc9e238a4..4c09e313bebc 100644 --- a/drivers/gpu/drm/virtio/virtgpu_plane.c +++ b/drivers/gpu/drm/virtio/virtgpu_plane.c @@ -26,7 +26,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_damage_helper.h> #include <drm/drm_fourcc.h> -#include <drm/drm_plane_helper.h> #include "virtgpu_drv.h" @@ -67,16 +66,9 @@ uint32_t virtio_gpu_translate_format(uint32_t drm_fourcc) return format; } -static void virtio_gpu_plane_destroy(struct drm_plane *plane) -{ - drm_plane_cleanup(plane); - kfree(plane); -} - static const struct drm_plane_funcs virtio_gpu_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, - .destroy = virtio_gpu_plane_destroy, .reset = drm_atomic_helper_plane_reset, .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, @@ -100,8 +92,8 @@ static int virtio_gpu_plane_atomic_check(struct drm_plane *plane, return PTR_ERR(crtc_state); ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, is_cursor, true); return ret; } @@ -266,14 +258,14 @@ static int virtio_gpu_plane_prepare_fb(struct drm_plane *plane, } static void virtio_gpu_plane_cleanup_fb(struct drm_plane *plane, - struct drm_plane_state *old_state) + struct drm_plane_state *state) { struct virtio_gpu_framebuffer *vgfb; - if (!plane->state->fb) + if (!state->fb) return; - vgfb = to_virtio_gpu_framebuffer(plane->state->fb); + vgfb = to_virtio_gpu_framebuffer(state->fb); if (vgfb->fence) { dma_fence_put(&vgfb->fence->f); vgfb->fence = NULL; @@ -379,11 +371,7 @@ struct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev, const struct drm_plane_helper_funcs *funcs; struct drm_plane *plane; const uint32_t *formats; - int ret, nformats; - - plane = kzalloc(sizeof(*plane), GFP_KERNEL); - if (!plane) - return ERR_PTR(-ENOMEM); + int nformats; if (type == DRM_PLANE_TYPE_CURSOR) { formats = virtio_gpu_cursor_formats; @@ -394,17 +382,13 @@ struct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev, nformats = ARRAY_SIZE(virtio_gpu_formats); funcs = &virtio_gpu_primary_helper_funcs; } - ret = drm_universal_plane_init(dev, plane, 1 << index, - &virtio_gpu_plane_funcs, - formats, nformats, - NULL, type, NULL); - if (ret) - goto err_plane_init; + + plane = drmm_universal_plane_alloc(dev, struct drm_plane, dev, + 1 << index, &virtio_gpu_plane_funcs, + formats, nformats, NULL, type, NULL); + if (IS_ERR(plane)) + return plane; drm_plane_helper_add(plane, funcs); return plane; - -err_plane_init: - kfree(plane); - return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index b7529b2b9883..9ff8660b50ad 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -322,7 +322,7 @@ static int virtio_gpu_queue_ctrl_sgs(struct virtio_gpu_device *vgdev, if (fence && vbuf->objs) virtio_gpu_array_unlock_resv(vbuf->objs); free_vbuf(vgdev, vbuf); - return -1; + return -ENODEV; } if (vgdev->has_indirect) @@ -386,7 +386,7 @@ static int virtio_gpu_queue_fenced_ctrl_buffer(struct virtio_gpu_device *vgdev, if (!sgt) { if (fence && vbuf->objs) virtio_gpu_array_unlock_resv(vbuf->objs); - return -1; + return -ENOMEM; } elemcnt += sg_ents; @@ -595,11 +595,10 @@ void virtio_gpu_cmd_transfer_to_host_2d(struct virtio_gpu_device *vgdev, struct virtio_gpu_transfer_to_host_2d *cmd_p; struct virtio_gpu_vbuffer *vbuf; bool use_dma_api = !virtio_has_dma_quirk(vgdev->vdev); - struct virtio_gpu_object_shmem *shmem = to_virtio_gpu_shmem(bo); - if (use_dma_api) - dma_sync_sgtable_for_device(vgdev->vdev->dev.parent, - shmem->pages, DMA_TO_DEVICE); + if (virtio_gpu_is_shmem(bo) && use_dma_api) + dma_sync_sgtable_for_device(&vgdev->vdev->dev, + bo->base.sgt, DMA_TO_DEVICE); cmd_p = virtio_gpu_alloc_cmd(vgdev, &vbuf, sizeof(*cmd_p)); memset(cmd_p, 0, sizeof(*cmd_p)); @@ -721,7 +720,7 @@ static int virtio_get_edid_block(void *data, u8 *buf, size_t start = block * EDID_LENGTH; if (start + len > le32_to_cpu(resp->size)) - return -1; + return -EINVAL; memcpy(buf, resp->edid + start, len); return 0; } @@ -1019,11 +1018,9 @@ void virtio_gpu_cmd_transfer_to_host_3d(struct virtio_gpu_device *vgdev, struct virtio_gpu_vbuffer *vbuf; bool use_dma_api = !virtio_has_dma_quirk(vgdev->vdev); - if (virtio_gpu_is_shmem(bo) && use_dma_api) { - struct virtio_gpu_object_shmem *shmem = to_virtio_gpu_shmem(bo); - dma_sync_sgtable_for_device(vgdev->vdev->dev.parent, - shmem->pages, DMA_TO_DEVICE); - } + if (virtio_gpu_is_shmem(bo) && use_dma_api) + dma_sync_sgtable_for_device(&vgdev->vdev->dev, + bo->base.sgt, DMA_TO_DEVICE); cmd_p = virtio_gpu_alloc_cmd(vgdev, &vbuf, sizeof(*cmd_p)); memset(cmd_p, 0, sizeof(*cmd_p)); diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c index d8eb674b49a6..8a810bfa1264 100644 --- a/drivers/gpu/drm/vkms/vkms_plane.c +++ b/drivers/gpu/drm/vkms/vkms_plane.c @@ -7,7 +7,6 @@ #include <drm/drm_fourcc.h> #include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_framebuffer_helper.h> -#include <drm/drm_plane_helper.h> #include "vkms_drv.h" @@ -139,8 +138,8 @@ static int vkms_plane_atomic_check(struct drm_plane *plane, can_position = true; ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, can_position, true); if (ret != 0) return ret; diff --git a/drivers/gpu/drm/vmwgfx/device_include/vm_basic_types.h b/drivers/gpu/drm/vmwgfx/device_include/vm_basic_types.h index 1f6e3bbc6605..f84376718086 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/vm_basic_types.h +++ b/drivers/gpu/drm/vmwgfx/device_include/vm_basic_types.h @@ -121,7 +121,7 @@ typedef __attribute__((aligned(32))) struct MKSGuestStatInfoEntry { * * Since the MKSGuestStatInfoEntry structures contain userlevel * pointers, the InstanceDescriptor also contains pointers to the - * begining of these sections allowing the host side code to correctly + * beginning of these sections allowing the host side code to correctly * interpret the pointers. * * Because the host side code never acknowledges anything back to the diff --git a/drivers/gpu/drm/vmwgfx/ttm_object.h b/drivers/gpu/drm/vmwgfx/ttm_object.h index 4c8700027c6d..1a2fa0f83f5f 100644 --- a/drivers/gpu/drm/vmwgfx/ttm_object.h +++ b/drivers/gpu/drm/vmwgfx/ttm_object.h @@ -96,7 +96,7 @@ struct ttm_object_device; * * This struct is intended to be used as a base struct for objects that * are visible to user-space. It provides a global name, race-safe - * access and refcounting, minimal access contol and hooks for unref actions. + * access and refcounting, minimal access control and hooks for unref actions. */ struct ttm_base_object { @@ -138,7 +138,7 @@ struct ttm_prime_object { * * @tfile: Pointer to a struct ttm_object_file. * @base: The struct ttm_base_object to initialize. - * @shareable: This object is shareable with other applcations. + * @shareable: This object is shareable with other applications. * (different @tfile pointers.) * @type: The object type. * @refcount_release: See the struct ttm_base_object description. diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c index 85a66014c2b6..822251aaab0a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c @@ -429,9 +429,9 @@ int vmw_bo_create_kernel(struct vmw_private *dev_priv, unsigned long size, drm_gem_private_object_init(vdev, &bo->base, size); - ret = ttm_bo_init_reserved(&dev_priv->bdev, bo, size, - ttm_bo_type_kernel, placement, 0, - &ctx, NULL, NULL, vmw_bo_default_destroy); + ret = ttm_bo_init_reserved(&dev_priv->bdev, bo, ttm_bo_type_kernel, + placement, 0, &ctx, NULL, NULL, + vmw_bo_default_destroy); if (unlikely(ret)) goto error_free; @@ -512,10 +512,8 @@ int vmw_bo_init(struct vmw_private *dev_priv, size = ALIGN(size, PAGE_SIZE); drm_gem_private_object_init(vdev, &vmw_bo->base.base, size); - ret = ttm_bo_init_reserved(bdev, &vmw_bo->base, size, - ttm_bo_type_device, - placement, - 0, &ctx, NULL, NULL, bo_free); + ret = ttm_bo_init_reserved(bdev, &vmw_bo->base, ttm_bo_type_device, + placement, 0, &ctx, NULL, NULL, bo_free); if (unlikely(ret)) { return ret; } @@ -729,7 +727,7 @@ int vmw_user_bo_lookup(struct drm_file *filp, * Any persistent usage of the object requires a refcount to be taken using * ttm_bo_reference_unless_doomed(). Iff this function returns successfully it * needs to be paired with vmw_user_bo_noref_release() and no sleeping- - * or scheduling functions may be called inbetween these function calls. + * or scheduling functions may be called in between these function calls. * * Return: A struct vmw_buffer_object pointer if successful or negative * error pointer on failure. diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c index 415774fde796..82ef58ccdd42 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c @@ -36,7 +36,7 @@ * @res: Refcounted pointer to a struct vmw_resource. * @hash: Hash entry for the manager hash table. * @head: List head used either by the staging list or the manager list - * of commited resources. + * of committed resources. * @state: Staging state of this resource entry. * @man: Pointer to a resource manager for this entry. */ @@ -51,9 +51,9 @@ struct vmw_cmdbuf_res { /** * struct vmw_cmdbuf_res_manager - Command buffer resource manager. * - * @resources: Hash table containing staged and commited command buffer + * @resources: Hash table containing staged and committed command buffer * resources - * @list: List of commited command buffer resources. + * @list: List of committed command buffer resources. * @dev_priv: Pointer to a device private structure. * * @resources and @list are protected by the cmdbuf mutex for now. @@ -118,7 +118,7 @@ static void vmw_cmdbuf_res_free(struct vmw_cmdbuf_res_manager *man, * This function commits a list of command buffer resource * additions or removals. * It is typically called when the execbuf ioctl call triggering these - * actions has commited the fifo contents to the device. + * actions has committed the fifo contents to the device. */ void vmw_cmdbuf_res_commit(struct list_head *list) { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 01a5b47e95f9..d7bd5eb1d3ac 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1398,18 +1398,6 @@ static void vmw_debugfs_resource_managers_init(struct vmw_private *vmw) root, "system_mob_ttm"); } -static unsigned long -vmw_get_unmapped_area(struct file *file, unsigned long uaddr, - unsigned long len, unsigned long pgoff, - unsigned long flags) -{ - struct drm_file *file_priv = file->private_data; - struct vmw_private *dev_priv = vmw_priv(file_priv->minor->dev); - - return drm_get_unmapped_area(file, uaddr, len, pgoff, flags, - dev_priv->drm.vma_offset_manager); -} - static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, void *ptr) { @@ -1576,7 +1564,6 @@ static const struct file_operations vmwgfx_driver_fops = { .compat_ioctl = vmw_compat_ioctl, #endif .llseek = noop_llseek, - .get_unmapped_area = vmw_get_unmapped_area, }; static const struct drm_driver driver = { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index d49de4905efa..f085dbd4736d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -1172,7 +1172,7 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv, vmw_validation_preload_bo(sw_context->ctx); vmw_bo = vmw_user_bo_noref_lookup(sw_context->filp, handle); - if (IS_ERR_OR_NULL(vmw_bo)) { + if (IS_ERR(vmw_bo)) { VMW_DEBUG_USER("Could not find or use MOB buffer.\n"); return PTR_ERR(vmw_bo); } @@ -1226,7 +1226,7 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv, vmw_validation_preload_bo(sw_context->ctx); vmw_bo = vmw_user_bo_noref_lookup(sw_context->filp, handle); - if (IS_ERR_OR_NULL(vmw_bo)) { + if (IS_ERR(vmw_bo)) { VMW_DEBUG_USER("Could not find or use GMR region.\n"); return PTR_ERR(vmw_bo); } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index ff2f735bbe7a..214829c32ed8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -29,7 +29,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_damage_helper.h> #include <drm/drm_fourcc.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_rect.h> #include <drm/drm_sysfs.h> #include <drm/drm_vblank.h> @@ -720,8 +719,8 @@ int vmw_du_primary_plane_atomic_check(struct drm_plane *plane, new_state->crtc); ret = drm_atomic_helper_check_plane_state(new_state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, false, true); if (!ret && new_fb) { @@ -762,8 +761,8 @@ int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane, new_state->crtc); ret = drm_atomic_helper_check_plane_state(new_state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, true, true); if (ret) return ret; @@ -2257,7 +2256,7 @@ out_fini: drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); mutex_unlock(&dev->mode_config.mutex); - + return 0; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 7046dfd0d1c6..85f86faa3243 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -70,7 +70,7 @@ struct vmw_du_update_plane { * * Some surface resource or buffer object need some extra cmd submission * like update GB image for proxy surface and define a GMRFB for screen - * object. That should should be done here as this callback will be + * object. That should be done here as this callback will be * called after FIFO allocation with the address of command buufer. * * This callback is optional. diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index e4347faccee0..b8761f16dd78 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -28,7 +28,6 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_fourcc.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_vblank.h> #include "vmwgfx_kms.h" diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index a7d62a4eb47b..f66caa540e14 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -525,7 +525,7 @@ void vmw_resource_unreserve(struct vmw_resource *res, * for a resource and in that case, allocate * one, reserve and validate it. * - * @ticket: The ww aqcquire context to use, or NULL if trylocking. + * @ticket: The ww acquire context to use, or NULL if trylocking. * @res: The resource for which to allocate a backup buffer. * @interruptible: Whether any sleeps during allocation should be * performed while interruptible. @@ -686,7 +686,7 @@ out_no_unbind: * @intr: Perform waits interruptible if possible. * @dirtying: Pending GPU operation will dirty the resource * - * On succesful return, any backup DMA buffer pointed to by @res->backup will + * On successful return, any backup DMA buffer pointed to by @res->backup will * be reserved and validated. * On hardware resource shortage, this function will repeatedly evict * resources of the same type until the validation succeeds. @@ -804,7 +804,7 @@ void vmw_resource_unbind_list(struct vmw_buffer_object *vbo) * @dx_query_mob: Buffer containing the DX query MOB * * Read back cached states from the device if they exist. This function - * assumings binding_mutex is held. + * assumes binding_mutex is held. */ int vmw_query_readback_all(struct vmw_buffer_object *dx_query_mob) { @@ -1125,7 +1125,7 @@ int vmw_resources_clean(struct vmw_buffer_object *vbo, pgoff_t start, } /* - * In order of increasing backup_offset, clean dirty resorces + * In order of increasing backup_offset, clean dirty resources * intersecting the range. */ while (found) { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index c89ad3a2d141..ecd3c2fc978b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -29,7 +29,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_damage_helper.h> #include <drm/drm_fourcc.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_vblank.h> #include "vmwgfx_kms.h" @@ -1383,6 +1382,6 @@ out_revert: vmw_validation_revert(&val_ctx); out_unref: vmw_validation_unref_lists(&val_ctx); - + return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_simple_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_simple_resource.c index 483ad544ea54..0d51b4542269 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_simple_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_simple_resource.c @@ -196,7 +196,7 @@ out_ret: * type. * * Returns: Refcounted pointer to the embedded struct vmw_resource if - * successfule. Error pointer otherwise. + * successful. Error pointer otherwise. */ struct vmw_resource * vmw_simple_resource_lookup(struct ttm_object_file *tfile, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index eb014b97d156..8650c3aea8f0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -29,7 +29,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_damage_helper.h> #include <drm/drm_fourcc.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_vblank.h> #include "vmwgfx_kms.h" diff --git a/drivers/gpu/drm/xlnx/Kconfig b/drivers/gpu/drm/xlnx/Kconfig index f9cf93c9e7e3..68ee897de9d7 100644 --- a/drivers/gpu/drm/xlnx/Kconfig +++ b/drivers/gpu/drm/xlnx/Kconfig @@ -8,7 +8,7 @@ config DRM_ZYNQMP_DPSUB select DMA_ENGINE select DRM_DISPLAY_DP_HELPER select DRM_DISPLAY_HELPER - select DRM_GEM_CMA_HELPER + select DRM_GEM_DMA_HELPER select DRM_KMS_HELPER select GENERIC_PHY help diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c index cc32aa89cf8f..bbb365f2d087 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c @@ -15,12 +15,11 @@ #include <drm/drm_blend.h> #include <drm/drm_crtc.h> #include <drm/drm_device.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> #include <drm/drm_managed.h> #include <drm/drm_plane.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_vblank.h> #include <linux/clk.h> @@ -1099,14 +1098,14 @@ static int zynqmp_disp_layer_update(struct zynqmp_disp_layer *layer, unsigned int height = state->crtc_h / (i ? info->vsub : 1); struct zynqmp_disp_layer_dma *dma = &layer->dmas[i]; struct dma_async_tx_descriptor *desc; - dma_addr_t paddr; + dma_addr_t dma_addr; - paddr = drm_fb_cma_get_gem_addr(state->fb, state, i); + dma_addr = drm_fb_dma_get_gem_addr(state->fb, state, i); dma->xt.numf = height; dma->sgl.size = width * info->cpp[i]; dma->sgl.icg = state->fb->pitches[i] - dma->sgl.size; - dma->xt.src_start = paddr; + dma->xt.src_start = dma_addr; dma->xt.frame_size = 1; dma->xt.dir = DMA_MEM_TO_DEV; dma->xt.src_sgl = true; @@ -1151,8 +1150,8 @@ zynqmp_disp_plane_atomic_check(struct drm_plane *plane, return drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, false, false); } diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c index 824b510e337b..1de2d927c32b 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c @@ -21,7 +21,7 @@ #include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> -#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_managed.h> #include <drm/drm_mode_config.h> @@ -47,7 +47,7 @@ static int zynqmp_dpsub_dumb_create(struct drm_file *file_priv, /* Enforce the alignment constraints of the DMA engine. */ args->pitch = ALIGN(pitch, dpsub->dma_align); - return drm_gem_cma_dumb_create_internal(file_priv, drm, args); + return drm_gem_dma_dumb_create_internal(file_priv, drm, args); } static struct drm_framebuffer * @@ -75,13 +75,13 @@ static const struct drm_mode_config_funcs zynqmp_dpsub_mode_config_funcs = { * DRM/KMS Driver */ -DEFINE_DRM_GEM_CMA_FOPS(zynqmp_dpsub_drm_fops); +DEFINE_DRM_GEM_DMA_FOPS(zynqmp_dpsub_drm_fops); static const struct drm_driver zynqmp_dpsub_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, - DRM_GEM_CMA_DRIVER_OPS_WITH_DUMB_CREATE(zynqmp_dpsub_dumb_create), + DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(zynqmp_dpsub_dumb_create), .fops = &zynqmp_dpsub_drm_fops, diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c index dbd1159a2ef0..ce04c38f6afd 100644 --- a/drivers/staging/sm750fb/sm750.c +++ b/drivers/staging/sm750fb/sm750.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 +#include <linux/aperture.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/errno.h> @@ -987,22 +988,16 @@ release_fb: static int lynxfb_kick_out_firmware_fb(struct pci_dev *pdev) { - struct apertures_struct *ap; + resource_size_t base = pci_resource_start(pdev, 0); + resource_size_t size = pci_resource_len(pdev, 0); bool primary = false; - ap = alloc_apertures(1); - if (!ap) - return -ENOMEM; - - ap->ranges[0].base = pci_resource_start(pdev, 0); - ap->ranges[0].size = pci_resource_len(pdev, 0); #ifdef CONFIG_X86 primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; #endif - remove_conflicting_framebuffers(ap, "sm750_fb1", primary); - kfree(ap); - return 0; + + return aperture_remove_conflicting_devices(base, size, primary, "sm750_fb1"); } static int lynxfb_pci_probe(struct pci_dev *pdev, diff --git a/drivers/video/aperture.c b/drivers/video/aperture.c index 538f2d40acda..9e6bcc03a1a4 100644 --- a/drivers/video/aperture.c +++ b/drivers/video/aperture.c @@ -2,15 +2,17 @@ #include <linux/aperture.h> #include <linux/device.h> -#include <linux/fb.h> /* for old fbdev helpers */ #include <linux/list.h> #include <linux/mutex.h> #include <linux/pci.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <linux/sysfb.h> #include <linux/types.h> #include <linux/vgaarb.h> +#include <video/vga.h> + /** * DOC: overview * @@ -283,26 +285,27 @@ static void aperture_detach_devices(resource_size_t base, resource_size_t size) int aperture_remove_conflicting_devices(resource_size_t base, resource_size_t size, bool primary, const char *name) { -#if IS_REACHABLE(CONFIG_FB) - struct apertures_struct *a; - int ret; - - a = alloc_apertures(1); - if (!a) - return -ENOMEM; - - a->ranges[0].base = base; - a->ranges[0].size = size; - - ret = remove_conflicting_framebuffers(a, name, primary); - kfree(a); - - if (ret) - return ret; -#endif + /* + * If a driver asked to unregister a platform device registered by + * sysfb, then can be assumed that this is a driver for a display + * that is set up by the system firmware and has a generic driver. + * + * Drivers for devices that don't have a generic driver will never + * ask for this, so let's assume that a real driver for the display + * was already probed and prevent sysfb to register devices later. + */ + sysfb_disable(); aperture_detach_devices(base, size); + /* + * If this is the primary adapter, there could be a VGA device + * that consumes the VGA framebuffer I/O range. Remove this device + * as well. + */ + if (primary) + aperture_detach_devices(VGA_FB_PHYS_BASE, VGA_FB_PHYS_SIZE); + return 0; } EXPORT_SYMBOL(aperture_remove_conflicting_devices); @@ -321,30 +324,36 @@ EXPORT_SYMBOL(aperture_remove_conflicting_devices); */ int aperture_remove_conflicting_pci_devices(struct pci_dev *pdev, const char *name) { + bool primary = false; resource_size_t base, size; int bar, ret; - /* - * WARNING: Apparently we must kick fbdev drivers before vgacon, - * otherwise the vga fbdev driver falls over. - */ -#if IS_REACHABLE(CONFIG_FB) - ret = remove_conflicting_pci_framebuffers(pdev, name); - if (ret) - return ret; +#ifdef CONFIG_X86 + primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; #endif - ret = vga_remove_vgacon(pdev); - if (ret) - return ret; for (bar = 0; bar < PCI_STD_NUM_BARS; ++bar) { if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) continue; + base = pci_resource_start(pdev, bar); size = pci_resource_len(pdev, bar); - aperture_detach_devices(base, size); + ret = aperture_remove_conflicting_devices(base, size, primary, name); + if (ret) + break; } + if (ret) + return ret; + + /* + * WARNING: Apparently we must kick fbdev drivers before vgacon, + * otherwise the vga fbdev driver falls over. + */ + ret = vga_remove_vgacon(pdev); + if (ret) + return ret; + return 0; } diff --git a/drivers/video/fbdev/arkfb.c b/drivers/video/fbdev/arkfb.c index a2a381631628..a317d9fe1d67 100644 --- a/drivers/video/fbdev/arkfb.c +++ b/drivers/video/fbdev/arkfb.c @@ -11,6 +11,7 @@ * Code is based on s3fb */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -956,6 +957,10 @@ static int ark_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) int rc; u8 regval; + rc = aperture_remove_conflicting_pci_devices(dev, "arkfb"); + if (rc < 0) + return rc; + /* Ignore secondary VGA device because there is no VGA arbitration */ if (! svga_primary_device(dev)) { dev_info(&(dev->dev), "ignoring secondary device\n"); diff --git a/drivers/video/fbdev/asiliantfb.c b/drivers/video/fbdev/asiliantfb.c index f8ef62542f7f..3818437a8f69 100644 --- a/drivers/video/fbdev/asiliantfb.c +++ b/drivers/video/fbdev/asiliantfb.c @@ -29,6 +29,7 @@ * more details. */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -545,6 +546,10 @@ static int asiliantfb_pci_init(struct pci_dev *dp, struct fb_info *p; int err; + err = aperture_remove_conflicting_pci_devices(dp, "asiliantfb"); + if (err) + return err; + if ((dp->resource[0].flags & IORESOURCE_MEM) == 0) return -ENODEV; addr = pci_resource_start(dp, 0); diff --git a/drivers/video/fbdev/aty/aty128fb.c b/drivers/video/fbdev/aty/aty128fb.c index b26c81233b6b..57e398fe7a81 100644 --- a/drivers/video/fbdev/aty/aty128fb.c +++ b/drivers/video/fbdev/aty/aty128fb.c @@ -23,7 +23,7 @@ * - Convert to new framebuffer API, * fix colormap setting at 16 bits/pixel (565) * - * Paul Mundt + * Paul Mundt * - PCI hotplug * * Jon Smirl <jonsmirl@yahoo.com> @@ -47,6 +47,7 @@ */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> @@ -520,13 +521,13 @@ static const struct fb_ops aty128fb_ops = { * - endian conversions may possibly be avoided by * using the other register aperture. TODO. */ -static inline u32 _aty_ld_le32(volatile unsigned int regindex, +static inline u32 _aty_ld_le32(volatile unsigned int regindex, const struct aty128fb_par *par) { return readl (par->regbase + regindex); } -static inline void _aty_st_le32(volatile unsigned int regindex, u32 val, +static inline void _aty_st_le32(volatile unsigned int regindex, u32 val, const struct aty128fb_par *par) { writel (val, par->regbase + regindex); @@ -559,12 +560,12 @@ static inline void _aty_st_8(unsigned int regindex, u8 val, static u32 _aty_ld_pll(unsigned int pll_index, const struct aty128fb_par *par) -{ +{ aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x3F); return aty_ld_le32(CLOCK_CNTL_DATA); } - + static void _aty_st_pll(unsigned int pll_index, u32 val, const struct aty128fb_par *par) { @@ -619,7 +620,7 @@ static int register_test(const struct aty128fb_par *par) aty_st_le32(BIOS_0_SCRATCH, 0xAAAAAAAA); if (aty_ld_le32(BIOS_0_SCRATCH) == 0xAAAAAAAA) - flag = 1; + flag = 1; } aty_st_le32(BIOS_0_SCRATCH, val); // restore value @@ -901,7 +902,7 @@ static void aty128_get_pllinfo(struct aty128fb_par *par, bios_hdr = BIOS_IN16(0x48); bios_pll = BIOS_IN16(bios_hdr + 0x30); - + par->constants.ppll_max = BIOS_IN32(bios_pll + 0x16); par->constants.ppll_min = BIOS_IN32(bios_pll + 0x12); par->constants.xclk = BIOS_IN16(bios_pll + 0x08); @@ -913,7 +914,7 @@ static void aty128_get_pllinfo(struct aty128fb_par *par, par->constants.xclk, par->constants.ref_divider, par->constants.ref_clk); -} +} #ifdef CONFIG_X86 static void __iomem *aty128_find_mem_vbios(struct aty128fb_par *par) @@ -925,7 +926,7 @@ static void __iomem *aty128_find_mem_vbios(struct aty128fb_par *par) */ u32 segstart; unsigned char __iomem *rom_base = NULL; - + for (segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) { rom_base = ioremap(segstart, 0x10000); if (rom_base == NULL) @@ -1118,12 +1119,12 @@ static int aty128_var_to_crtc(const struct fb_var_screeninfo *var, v_sync_wid = 1; else if (v_sync_wid > 0x1f) /* 0x1f = max vwidth */ v_sync_wid = 0x1f; - + v_sync_strt = v_disp + lower; h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; - + c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0; crtc->gen_cntl = 0x3000000L | c_sync | (dst << 8); @@ -1301,11 +1302,11 @@ static void aty128_set_lcd_enable(struct aty128fb_par *par, int on) aty_st_le32(LVDS_GEN_CNTL, reg); #ifdef CONFIG_FB_ATY128_BACKLIGHT aty128_bl_set_power(info, FB_BLANK_UNBLANK); -#endif +#endif } else { #ifdef CONFIG_FB_ATY128_BACKLIGHT aty128_bl_set_power(info, FB_BLANK_POWERDOWN); -#endif +#endif reg = aty_ld_le32(LVDS_GEN_CNTL); reg |= LVDS_DISPLAY_DIS; aty_st_le32(LVDS_GEN_CNTL, reg); @@ -1481,7 +1482,7 @@ static int aty128_ddafifo(struct aty128_ddafifo *dsp, * This actually sets the video mode. */ static int aty128fb_set_par(struct fb_info *info) -{ +{ struct aty128fb_par *par = info->par; u32 config; int err; @@ -1595,7 +1596,7 @@ static int aty128_encode_var(struct fb_var_screeninfo *var, var->accel_flags = par->accel_flags; return 0; -} +} static int aty128fb_check_var(struct fb_var_screeninfo *var, @@ -1979,12 +1980,12 @@ static int aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent) /* PowerBook Titanium */ if (of_machine_is_compatible("PowerBook3,2")) default_vmode = VMODE_1152_768_60; - - if (default_cmode > 16) + + if (default_cmode > 16) default_cmode = CMODE_32; - else if (default_cmode > 8) + else if (default_cmode > 8) default_cmode = CMODE_16; - else + else default_cmode = CMODE_8; if (mac_vmode_to_var(default_vmode, default_cmode, &var)) @@ -1994,7 +1995,7 @@ static int aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent) #endif /* CONFIG_PPC_PMAC */ { if (mode_option) - if (fb_find_mode(&var, info, mode_option, NULL, + if (fb_find_mode(&var, info, mode_option, NULL, 0, &defaultmode, 8) == 0) var = default_var; } @@ -2055,6 +2056,10 @@ static int aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent) void __iomem *bios = NULL; #endif + err = aperture_remove_conflicting_pci_devices(pdev, "aty128fb"); + if (err) + return err; + /* Enable device in PCI config */ if ((err = pci_enable_device(pdev))) { printk(KERN_ERR "aty128fb: Cannot enable PCI device: %d\n", @@ -2301,7 +2306,7 @@ static int aty128fb_ioctl(struct fb_info *info, u_int cmd, u_long arg) struct aty128fb_par *par = info->par; u32 value; int rc; - + switch (cmd) { case FBIO_ATY128_SET_MIRROR: if (par->chip_gen != rage_M3) @@ -2313,8 +2318,8 @@ static int aty128fb_ioctl(struct fb_info *info, u_int cmd, u_long arg) par->crt_on = (value & 0x02) != 0; if (!par->crt_on && !par->lcd_on) par->lcd_on = 1; - aty128_set_crt_enable(par, par->crt_on); - aty128_set_lcd_enable(par, par->lcd_on); + aty128_set_crt_enable(par, par->crt_on); + aty128_set_lcd_enable(par, par->lcd_on); return 0; case FBIO_ATY128_GET_MIRROR: if (par->chip_gen != rage_M3) @@ -2331,7 +2336,7 @@ static void aty128_set_suspend(struct aty128fb_par *par, int suspend) if (!par->pdev->pm_cap) return; - + /* Set the chip into the appropriate suspend mode (we use D2, * D3 would require a complete re-initialisation of the chip, * including PCI config registers, clocks, AGP configuration, ...) @@ -2376,12 +2381,12 @@ static int aty128_pci_suspend_late(struct device *dev, pm_message_t state) */ return 0; #endif /* CONFIG_PPC_PMAC */ - + if (state.event == pdev->dev.power.power_state.event) return 0; printk(KERN_DEBUG "aty128fb: suspending...\n"); - + console_lock(); fb_set_suspend(info, 1); diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c index a3e6faed7745..4804b6e9f3f4 100644 --- a/drivers/video/fbdev/aty/atyfb_base.c +++ b/drivers/video/fbdev/aty/atyfb_base.c @@ -48,6 +48,7 @@ ******************************************************************************/ +#include <linux/aperture.h> #include <linux/compat.h> #include <linux/module.h> #include <linux/moduleparam.h> @@ -3533,7 +3534,11 @@ static int atyfb_pci_probe(struct pci_dev *pdev, struct fb_info *info; struct resource *rp; struct atyfb_par *par; - int rc = -ENOMEM; + int rc; + + rc = aperture_remove_conflicting_pci_devices(pdev, "atyfb"); + if (rc) + return rc; /* Enable device in PCI config */ if (pci_enable_device(pdev)) { diff --git a/drivers/video/fbdev/aty/radeon_base.c b/drivers/video/fbdev/aty/radeon_base.c index 6851f47613e1..0a8199985d52 100644 --- a/drivers/video/fbdev/aty/radeon_base.c +++ b/drivers/video/fbdev/aty/radeon_base.c @@ -7,7 +7,7 @@ * Copyright 2000 Ani Joshi <ajoshi@kernel.crashing.org> * * i2c bits from Luca Tettamanti <kronos@kronoz.cjb.net> - * + * * Special thanks to ATI DevRel team for their hardware donations. * * ...Insert GPL boilerplate here... @@ -54,6 +54,7 @@ #include "radeonfb.h" +#include <linux/aperture.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> @@ -110,7 +111,7 @@ static const struct pci_device_id radeonfb_pci_table[] = { /* Radeon IGP320M (U1) */ CHIP_DEF(PCI_CHIP_RS100_4336, RS100, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), /* Radeon IGP320 (A3) */ - CHIP_DEF(PCI_CHIP_RS100_4136, RS100, CHIP_HAS_CRTC2 | CHIP_IS_IGP), + CHIP_DEF(PCI_CHIP_RS100_4136, RS100, CHIP_HAS_CRTC2 | CHIP_IS_IGP), /* IGP330M/340M/350M (U2) */ CHIP_DEF(PCI_CHIP_RS200_4337, RS200, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), /* IGP330/340/350 (A4) */ @@ -240,7 +241,7 @@ typedef struct { * interfere with anything */ static reg_val common_regs[] = { - { OVR_CLR, 0 }, + { OVR_CLR, 0 }, { OVR_WID_LEFT_RIGHT, 0 }, { OVR_WID_TOP_BOTTOM, 0 }, { OV0_SCALE_CNTL, 0 }, @@ -255,7 +256,7 @@ static reg_val common_regs[] = { /* * globals */ - + static char *mode_option; static char *monitor_layout; static bool noaccel = 0; @@ -422,7 +423,7 @@ static int radeon_map_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev) * ROM somewhere in the first meg. We will just ignore the copy * and use the ROM directly. */ - + /* Fix from ATI for problem with Radeon hardware not leaving ROM enabled */ unsigned int temp; temp = INREG(MPP_TB_CONFIG); @@ -430,14 +431,14 @@ static int radeon_map_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev) temp |= 0x04 << 24; OUTREG(MPP_TB_CONFIG, temp); temp = INREG(MPP_TB_CONFIG); - + rom = pci_map_rom(dev, &rom_size); if (!rom) { printk(KERN_ERR "radeonfb (%s): ROM failed to map\n", pci_name(rinfo->pdev)); return -ENOMEM; } - + rinfo->bios_seg = rom; /* Very simple test to make sure it appeared */ @@ -515,7 +516,7 @@ static int radeon_find_mem_vbios(struct radeonfb_info *rinfo) */ u32 segstart; void __iomem *rom_base = NULL; - + for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) { rom_base = ioremap(segstart, 0x10000); if (rom_base == NULL) @@ -605,16 +606,16 @@ static int radeon_probe_pll_params(struct radeonfb_info *rinfo) for(i=0; i<1000000; i++) if (((INREG(CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) == 0) break; - + stop_time = ktime_get(); - + local_irq_enable(); total_usecs = ktime_us_delta(stop_time, start_time); if (total_usecs >= 10 * USEC_PER_SEC || total_usecs == 0) return -1; hz = USEC_PER_SEC/(u32)total_usecs; - + hTotal = ((INREG(CRTC_H_TOTAL_DISP) & 0x1ff) + 1) * 8; vTotal = ((INREG(CRTC_V_TOTAL_DISP) & 0x3ff) + 1); vclk = (long long)hTotal * (long long)vTotal * hz; @@ -662,7 +663,7 @@ static int radeon_probe_pll_params(struct radeonfb_info *rinfo) denom *= 3; break; case 6: - denom *= 6; + denom *= 6; break; case 7: denom *= 12; @@ -878,7 +879,7 @@ static int radeonfb_check_var (struct fb_var_screeninfo *var, struct fb_info *in v.green.length = 6; v.blue.length = 5; v.transp.offset = v.transp.length = 0; - break; + break; case 24: nom = 4; den = 1; @@ -908,7 +909,7 @@ static int radeonfb_check_var (struct fb_var_screeninfo *var, struct fb_info *in v.yres_virtual = v.yres; if (v.xres_virtual < v.xres) v.xres_virtual = v.xres; - + /* XXX I'm adjusting xres_virtual to the pitch, that may help XFree * with some panels, though I don't quite like this solution @@ -929,14 +930,14 @@ static int radeonfb_check_var (struct fb_var_screeninfo *var, struct fb_info *in if (v.xoffset > v.xres_virtual - v.xres) v.xoffset = v.xres_virtual - v.xres - 1; - + if (v.yoffset > v.yres_virtual - v.yres) v.yoffset = v.yres_virtual - v.yres - 1; - + v.red.msb_right = v.green.msb_right = v.blue.msb_right = v.transp.offset = v.transp.length = v.transp.msb_right = 0; - + memcpy(var, &v, sizeof(v)); return 0; @@ -951,7 +952,7 @@ static int radeonfb_pan_display (struct fb_var_screeninfo *var, if ((var->xoffset + info->var.xres > info->var.xres_virtual) || (var->yoffset + info->var.yres > info->var.yres_virtual)) return -EINVAL; - + if (rinfo->asleep) return 0; @@ -1151,7 +1152,7 @@ static int radeonfb_blank (int blank, struct fb_info *info) if (rinfo->asleep) return 0; - + return radeon_screen_blank(rinfo, blank, 0); } @@ -1401,7 +1402,7 @@ static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_reg } else { /* R300 uses ref_div_acc field as real ref divider */ OUTPLLP(PPLL_REF_DIV, - (mode->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT), + (mode->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT), ~R300_PPLL_REF_DIV_ACC_MASK); } } else @@ -1423,7 +1424,7 @@ static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_reg workaround shouldn't have any effect on them. */ for (i = 0; (i < 10000 && INPLL(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R); i++) ; - + OUTPLL(HTOTAL_CNTL, 0); /* Clear reset & atomic update */ @@ -1510,7 +1511,7 @@ void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode, radeon_fifo_wait(2); OUTPLL(VCLK_ECP_CNTL, mode->vclk_ecp_cntl); - + return; } @@ -1735,7 +1736,7 @@ static int radeonfb_set_par(struct fb_info *info) /* Clear auto-center etc... */ newmode->crtc_more_cntl = rinfo->init_state.crtc_more_cntl; newmode->crtc_more_cntl &= 0xfffffff0; - + if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) { newmode->crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN; if (mirror) @@ -1793,7 +1794,7 @@ static int radeonfb_set_par(struct fb_info *info) newmode->surface_cntl |= NONSURF_AP0_SWP_16BPP; newmode->surface_cntl |= NONSURF_AP1_SWP_16BPP; break; - case 24: + case 24: case 32: newmode->surface_cntl |= NONSURF_AP0_SWP_32BPP; newmode->surface_cntl |= NONSURF_AP1_SWP_32BPP; @@ -2028,7 +2029,7 @@ static void fixup_memory_mappings(struct radeonfb_info *rinfo) } save_crtc_gen_cntl = INREG(CRTC_GEN_CNTL); save_crtc_ext_cntl = INREG(CRTC_EXT_CNTL); - + OUTREG(CRTC_EXT_CNTL, save_crtc_ext_cntl | CRTC_DISPLAY_DIS); OUTREG(CRTC_GEN_CNTL, save_crtc_gen_cntl | CRTC_DISP_REQ_EN_B); mdelay(100); @@ -2038,7 +2039,7 @@ static void fixup_memory_mappings(struct radeonfb_info *rinfo) #ifdef SET_MC_FB_FROM_APERTURE /* Set framebuffer to be at the same address as set in PCI BAR */ - OUTREG(MC_FB_LOCATION, + OUTREG(MC_FB_LOCATION, ((aper_base + aper_size - 1) & 0xffff0000) | (aper_base >> 16)); rinfo->fb_local_base = aper_base; #else @@ -2079,7 +2080,7 @@ static void fixup_memory_mappings(struct radeonfb_info *rinfo) OUTREG(CRTC_GEN_CNTL, save_crtc_gen_cntl); OUTREG(CRTC_EXT_CNTL, save_crtc_ext_cntl); if (rinfo->has_CRTC2) - OUTREG(CRTC2_GEN_CNTL, save_crtc2_gen_cntl); + OUTREG(CRTC2_GEN_CNTL, save_crtc2_gen_cntl); pr_debug("aper_base: %08x MC_FB_LOC to: %08x, MC_AGP_LOC to: %08x\n", aper_base, @@ -2239,20 +2240,10 @@ static const struct bin_attribute edid2_attr = { static int radeon_kick_out_firmware_fb(struct pci_dev *pdev) { - struct apertures_struct *ap; - - ap = alloc_apertures(1); - if (!ap) - return -ENOMEM; - - ap->ranges[0].base = pci_resource_start(pdev, 0); - ap->ranges[0].size = pci_resource_len(pdev, 0); + resource_size_t base = pci_resource_start(pdev, 0); + resource_size_t size = pci_resource_len(pdev, 0); - remove_conflicting_framebuffers(ap, KBUILD_MODNAME, false); - - kfree(ap); - - return 0; + return aperture_remove_conflicting_devices(base, size, false, KBUILD_MODNAME); } static int radeonfb_pci_register(struct pci_dev *pdev, @@ -2265,7 +2256,7 @@ static int radeonfb_pci_register(struct pci_dev *pdev, int err = 0; pr_debug("radeonfb_pci_register BEGIN\n"); - + /* Enable device in PCI config */ ret = pci_enable_device(pdev); if (ret < 0) { @@ -2280,9 +2271,9 @@ static int radeonfb_pci_register(struct pci_dev *pdev, goto err_disable; } rinfo = info->par; - rinfo->info = info; + rinfo->info = info; rinfo->pdev = pdev; - + spin_lock_init(&rinfo->reg_lock); timer_setup(&rinfo->lvds_timer, radeon_lvds_timer_func, 0); @@ -2521,7 +2512,7 @@ static void radeonfb_pci_unregister(struct pci_dev *pdev) { struct fb_info *info = pci_get_drvdata(pdev); struct radeonfb_info *rinfo = info->par; - + if (!rinfo) return; @@ -2540,7 +2531,7 @@ static void radeonfb_pci_unregister(struct pci_dev *pdev) iounmap(rinfo->mmio_base); iounmap(rinfo->fb_base); - + pci_release_region(pdev, 2); pci_release_region(pdev, 0); @@ -2550,7 +2541,7 @@ static void radeonfb_pci_unregister(struct pci_dev *pdev) fb_destroy_modedb(rinfo->mon1_modedb); #ifdef CONFIG_FB_RADEON_I2C radeon_delete_i2c_busses(rinfo); -#endif +#endif fb_dealloc_cmap(&info->cmap); framebuffer_release(info); } diff --git a/drivers/video/fbdev/carminefb.c b/drivers/video/fbdev/carminefb.c index 3a1c2e0739a1..4651b48a87f9 100644 --- a/drivers/video/fbdev/carminefb.c +++ b/drivers/video/fbdev/carminefb.c @@ -7,6 +7,7 @@ * - FB1 is display 1 with unique memory area * - both display use 32 bit colors */ +#include <linux/aperture.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/fb.h> @@ -614,6 +615,10 @@ static int carminefb_probe(struct pci_dev *dev, const struct pci_device_id *ent) struct fb_info *info; int ret; + ret = aperture_remove_conflicting_pci_devices(dev, "carminefb"); + if (ret) + return ret; + ret = pci_enable_device(dev); if (ret) return ret; diff --git a/drivers/video/fbdev/chipsfb.c b/drivers/video/fbdev/chipsfb.c index 393894af26f8..5ad64714d39e 100644 --- a/drivers/video/fbdev/chipsfb.c +++ b/drivers/video/fbdev/chipsfb.c @@ -14,6 +14,7 @@ * more details. */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -122,7 +123,7 @@ static int chipsfb_set_par(struct fb_info *info) info->var.blue.offset = 0; info->var.red.length = info->var.green.length = info->var.blue.length = 5; - + } else { /* p->var.bits_per_pixel == 8 */ write_cr(0x13, 100); // Set line length (doublewords) @@ -131,13 +132,13 @@ static int chipsfb_set_par(struct fb_info *info) write_xr(0x20, 0x00); // 8 bit blitter mode info->fix.line_length = 800; - info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; info->var.red.offset = info->var.green.offset = info->var.blue.offset = 0; info->var.red.length = info->var.green.length = info->var.blue.length = 8; - + } return 0; } @@ -351,7 +352,11 @@ static int chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) struct fb_info *p; unsigned long addr; unsigned short cmd; - int rc = -ENODEV; + int rc; + + rc = aperture_remove_conflicting_pci_devices(dp, "chipsfb"); + if (rc) + return rc; if (pci_enable_device(dp) < 0) { dev_err(&dp->dev, "Cannot enable PCI device\n"); diff --git a/drivers/video/fbdev/cirrusfb.c b/drivers/video/fbdev/cirrusfb.c index a41a75841e10..851367e159c0 100644 --- a/drivers/video/fbdev/cirrusfb.c +++ b/drivers/video/fbdev/cirrusfb.c @@ -34,6 +34,7 @@ * */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -2085,6 +2086,10 @@ static int cirrusfb_pci_register(struct pci_dev *pdev, unsigned long board_addr, board_size; int ret; + ret = aperture_remove_conflicting_pci_devices(pdev, "cirrusfb"); + if (ret) + return ret; + ret = pci_enable_device(pdev); if (ret < 0) { printk(KERN_ERR "cirrusfb: Cannot enable PCI device\n"); diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 02b0cf2cfafe..1e70d8c67653 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -13,13 +13,13 @@ #include <linux/module.h> +#include <linux/aperture.h> #include <linux/compat.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/major.h> #include <linux/slab.h> -#include <linux/sysfb.h> #include <linux/mm.h> #include <linux/mman.h> #include <linux/vt.h> @@ -40,6 +40,7 @@ #include <asm/fb.h> +#include <video/vga.h> /* * Frame buffer device initialization and setup routines @@ -50,10 +51,10 @@ static DEFINE_MUTEX(registration_lock); struct fb_info *registered_fb[FB_MAX] __read_mostly; -EXPORT_SYMBOL(registered_fb); - int num_registered_fb __read_mostly; -EXPORT_SYMBOL(num_registered_fb); +#define for_each_registered_fb(i) \ + for (i = 0; i < FB_MAX; i++) \ + if (!registered_fb[i]) {} else bool fb_center_logo __read_mostly; @@ -1525,103 +1526,6 @@ static int fb_check_foreignness(struct fb_info *fi) return 0; } -static bool apertures_overlap(struct aperture *gen, struct aperture *hw) -{ - /* is the generic aperture base the same as the HW one */ - if (gen->base == hw->base) - return true; - /* is the generic aperture base inside the hw base->hw base+size */ - if (gen->base > hw->base && gen->base < hw->base + hw->size) - return true; - return false; -} - -static bool fb_do_apertures_overlap(struct apertures_struct *gena, - struct apertures_struct *hwa) -{ - int i, j; - if (!hwa || !gena) - return false; - - for (i = 0; i < hwa->count; ++i) { - struct aperture *h = &hwa->ranges[i]; - for (j = 0; j < gena->count; ++j) { - struct aperture *g = &gena->ranges[j]; - printk(KERN_DEBUG "checking generic (%llx %llx) vs hw (%llx %llx)\n", - (unsigned long long)g->base, - (unsigned long long)g->size, - (unsigned long long)h->base, - (unsigned long long)h->size); - if (apertures_overlap(g, h)) - return true; - } - } - - return false; -} - -static void do_unregister_framebuffer(struct fb_info *fb_info); - -#define VGA_FB_PHYS 0xA0000 -static void do_remove_conflicting_framebuffers(struct apertures_struct *a, - const char *name, bool primary) -{ - int i; - -restart_removal: - /* check all firmware fbs and kick off if the base addr overlaps */ - for_each_registered_fb(i) { - struct apertures_struct *gen_aper; - struct device *device; - - if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE)) - continue; - - gen_aper = registered_fb[i]->apertures; - device = registered_fb[i]->device; - if (fb_do_apertures_overlap(gen_aper, a) || - (primary && gen_aper && gen_aper->count && - gen_aper->ranges[0].base == VGA_FB_PHYS)) { - - printk(KERN_INFO "fb%d: switching to %s from %s\n", - i, name, registered_fb[i]->fix.id); - - /* - * If we kick-out a firmware driver, we also want to remove - * the underlying platform device, such as simple-framebuffer, - * VESA, EFI, etc. A native driver will then be able to - * allocate the memory range. - * - * If it's not a platform device, at least print a warning. A - * fix would add code to remove the device from the system. For - * framebuffers without any Linux device, print a warning as - * well. - */ - if (!device) { - pr_warn("fb%d: no device set\n", i); - do_unregister_framebuffer(registered_fb[i]); - } else if (dev_is_platform(device)) { - /* - * Drop the lock because if the device is unregistered, its - * driver will call to unregister_framebuffer(), that takes - * this lock. - */ - mutex_unlock(®istration_lock); - platform_device_unregister(to_platform_device(device)); - mutex_lock(®istration_lock); - } else { - pr_warn("fb%d: cannot remove device\n", i); - do_unregister_framebuffer(registered_fb[i]); - } - /* - * Restart the removal loop now that the device has been - * unregistered and its associated framebuffer gone. - */ - goto restart_removal; - } - } -} - static int do_register_framebuffer(struct fb_info *fb_info) { int i; @@ -1630,10 +1534,6 @@ static int do_register_framebuffer(struct fb_info *fb_info) if (fb_check_foreignness(fb_info)) return -ENOSYS; - do_remove_conflicting_framebuffers(fb_info->apertures, - fb_info->fix.id, - fb_is_primary_device(fb_info)); - if (num_registered_fb == FB_MAX) return -ENXIO; @@ -1752,100 +1652,31 @@ static void do_unregister_framebuffer(struct fb_info *fb_info) put_fb_info(fb_info); } -/** - * remove_conflicting_framebuffers - remove firmware-configured framebuffers - * @a: memory range, users of which are to be removed - * @name: requesting driver name - * @primary: also kick vga16fb if present - * - * This function removes framebuffer devices (initialized by firmware/bootloader) - * which use memory range described by @a. If @a is NULL all such devices are - * removed. - */ -int remove_conflicting_framebuffers(struct apertures_struct *a, - const char *name, bool primary) +static int fb_aperture_acquire_for_platform_device(struct fb_info *fb_info) { - bool do_free = false; - - if (!a) { - a = alloc_apertures(1); - if (!a) - return -ENOMEM; - - a->ranges[0].base = 0; - a->ranges[0].size = ~0; - do_free = true; - } - - /* - * If a driver asked to unregister a platform device registered by - * sysfb, then can be assumed that this is a driver for a display - * that is set up by the system firmware and has a generic driver. - * - * Drivers for devices that don't have a generic driver will never - * ask for this, so let's assume that a real driver for the display - * was already probed and prevent sysfb to register devices later. - */ - sysfb_disable(); - - mutex_lock(®istration_lock); - do_remove_conflicting_framebuffers(a, name, primary); - mutex_unlock(®istration_lock); - - if (do_free) - kfree(a); - - return 0; -} -EXPORT_SYMBOL(remove_conflicting_framebuffers); + struct apertures_struct *ap = fb_info->apertures; + struct device *dev = fb_info->device; + struct platform_device *pdev; + unsigned int i; + int ret; -/** - * remove_conflicting_pci_framebuffers - remove firmware-configured framebuffers for PCI devices - * @pdev: PCI device - * @name: requesting driver name - * - * This function removes framebuffer devices (eg. initialized by firmware) - * using memory range configured for any of @pdev's memory bars. - * - * The function assumes that PCI device with shadowed ROM drives a primary - * display and so kicks out vga16fb. - */ -int remove_conflicting_pci_framebuffers(struct pci_dev *pdev, const char *name) -{ - struct apertures_struct *ap; - bool primary = false; - int err, idx, bar; + if (!ap) + return 0; - for (idx = 0, bar = 0; bar < PCI_STD_NUM_BARS; bar++) { - if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) - continue; - idx++; - } + if (!dev_is_platform(dev)) + return 0; - ap = alloc_apertures(idx); - if (!ap) - return -ENOMEM; + pdev = to_platform_device(dev); - for (idx = 0, bar = 0; bar < PCI_STD_NUM_BARS; bar++) { - if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) - continue; - ap->ranges[idx].base = pci_resource_start(pdev, bar); - ap->ranges[idx].size = pci_resource_len(pdev, bar); - pci_dbg(pdev, "%s: bar %d: 0x%lx -> 0x%lx\n", __func__, bar, - (unsigned long)pci_resource_start(pdev, bar), - (unsigned long)pci_resource_end(pdev, bar)); - idx++; + for (ret = 0, i = 0; i < ap->count; ++i) { + ret = devm_aperture_acquire_for_platform_device(pdev, ap->ranges[i].base, + ap->ranges[i].size); + if (ret) + break; } -#ifdef CONFIG_X86 - primary = pdev->resource[PCI_ROM_RESOURCE].flags & - IORESOURCE_ROM_SHADOW; -#endif - err = remove_conflicting_framebuffers(ap, name, primary); - kfree(ap); - return err; + return ret; } -EXPORT_SYMBOL(remove_conflicting_pci_framebuffers); /** * register_framebuffer - registers a frame buffer device @@ -1861,6 +1692,12 @@ register_framebuffer(struct fb_info *fb_info) { int ret; + if (fb_info->flags & FBINFO_MISC_FIRMWARE) { + ret = fb_aperture_acquire_for_platform_device(fb_info); + if (ret) + return ret; + } + mutex_lock(®istration_lock); ret = do_register_framebuffer(fb_info); mutex_unlock(®istration_lock); diff --git a/drivers/video/fbdev/cyber2000fb.c b/drivers/video/fbdev/cyber2000fb.c index d45355b9a58c..be7bcf95c96a 100644 --- a/drivers/video/fbdev/cyber2000fb.c +++ b/drivers/video/fbdev/cyber2000fb.c @@ -33,6 +33,7 @@ * (which, incidentally, is about the same saving as a 2.5in hard disk * entering standby mode.) */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -1720,6 +1721,10 @@ static int cyberpro_pci_probe(struct pci_dev *dev, sprintf(name, "CyberPro%4X", id->device); + err = aperture_remove_conflicting_pci_devices(dev, name); + if (err) + return err; + err = pci_enable_device(dev); if (err) return err; diff --git a/drivers/video/fbdev/geode/gx1fb_core.c b/drivers/video/fbdev/geode/gx1fb_core.c index 5d34d89fb665..4cac7e3bb1a0 100644 --- a/drivers/video/fbdev/geode/gx1fb_core.c +++ b/drivers/video/fbdev/geode/gx1fb_core.c @@ -6,6 +6,7 @@ * Copyright (C) 2005 Arcom Control Systems Ltd. */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -320,6 +321,10 @@ static int gx1fb_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct fb_info *info; int ret; + ret = aperture_remove_conflicting_pci_devices(pdev, "gx1fb"); + if (ret) + return ret; + info = gx1fb_init_fbinfo(&pdev->dev); if (!info) return -ENOMEM; diff --git a/drivers/video/fbdev/geode/gxfb_core.c b/drivers/video/fbdev/geode/gxfb_core.c index 44089b331f91..2527bd80ec5f 100644 --- a/drivers/video/fbdev/geode/gxfb_core.c +++ b/drivers/video/fbdev/geode/gxfb_core.c @@ -15,6 +15,7 @@ * * 16 MiB of framebuffer memory is assumed to be available. */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -364,6 +365,10 @@ static int gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct fb_videomode *modedb_ptr; unsigned int modedb_size; + ret = aperture_remove_conflicting_pci_devices(pdev, "gxfb"); + if (ret) + return ret; + info = gxfb_init_fbinfo(&pdev->dev); if (!info) return -ENOMEM; diff --git a/drivers/video/fbdev/geode/lxfb_core.c b/drivers/video/fbdev/geode/lxfb_core.c index 66c81262d18f..9d26592dbfce 100644 --- a/drivers/video/fbdev/geode/lxfb_core.c +++ b/drivers/video/fbdev/geode/lxfb_core.c @@ -6,6 +6,7 @@ * Built from gxfb (which is Copyright (C) 2006 Arcom Control Systems Ltd.) */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -484,6 +485,10 @@ static int lxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct fb_videomode *modedb_ptr; unsigned int modedb_size; + ret = aperture_remove_conflicting_pci_devices(pdev, "lxfb"); + if (ret) + return ret; + info = lxfb_init_fbinfo(&pdev->dev); if (info == NULL) diff --git a/drivers/video/fbdev/gxt4500.c b/drivers/video/fbdev/gxt4500.c index e5475ae1e158..f0d36a4fdaef 100644 --- a/drivers/video/fbdev/gxt4500.c +++ b/drivers/video/fbdev/gxt4500.c @@ -6,6 +6,7 @@ * Copyright (C) 2006 Paul Mackerras, IBM Corp. <paulus@samba.org> */ +#include <linux/aperture.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/fb.h> @@ -621,6 +622,10 @@ static int gxt4500_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct fb_var_screeninfo var; enum gxt_cards cardtype; + err = aperture_remove_conflicting_pci_devices(pdev, "gxt4500fb"); + if (err) + return err; + err = pci_enable_device(pdev); if (err) { dev_err(&pdev->dev, "gxt4500: cannot enable PCI device: %d\n", diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c index 886c564787f1..a0e1d70b90d7 100644 --- a/drivers/video/fbdev/hyperv_fb.c +++ b/drivers/video/fbdev/hyperv_fb.c @@ -45,6 +45,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/vmalloc.h> @@ -1074,8 +1075,9 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info) info->screen_size = dio_fb_size; getmem_done: - remove_conflicting_framebuffers(info->apertures, - KBUILD_MODNAME, false); + aperture_remove_conflicting_devices(info->apertures->ranges[0].base, + info->apertures->ranges[0].size, + false, KBUILD_MODNAME); if (gen2vm) { /* framebuffer is reallocated, clear screen_info to avoid misuse from kexec */ diff --git a/drivers/video/fbdev/i740fb.c b/drivers/video/fbdev/i740fb.c index 7f09a0daaaa2..199f786f9eed 100644 --- a/drivers/video/fbdev/i740fb.c +++ b/drivers/video/fbdev/i740fb.c @@ -12,6 +12,7 @@ * i740fb by Patrick LERDA, v0.9 */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -1013,6 +1014,10 @@ static int i740fb_probe(struct pci_dev *dev, const struct pci_device_id *ent) bool found = false; u8 *edid; + ret = aperture_remove_conflicting_pci_devices(dev, "i740fb"); + if (ret) + return ret; + info = framebuffer_alloc(sizeof(struct i740fb_par), &(dev->dev)); if (!info) return -ENOMEM; diff --git a/drivers/video/fbdev/i810/i810_main.c b/drivers/video/fbdev/i810/i810_main.c index 13bbf7fe13bf..ff09f8c20bfc 100644 --- a/drivers/video/fbdev/i810/i810_main.c +++ b/drivers/video/fbdev/i810/i810_main.c @@ -2,12 +2,12 @@ * linux/drivers/video/i810_main.c -- Intel 810 frame buffer device * * Copyright (C) 2001 Antonino Daplas<adaplas@pol.net> - * All Rights Reserved + * All Rights Reserved * * Contributors: * Michael Vogt <mvogt@acm.org> - added support for Intel 815 chipsets - * and enabling the power-on state of - * external VGA connectors for + * and enabling the power-on state of + * external VGA connectors for * secondary displays * * Fredrik Andersson <krueger@shell.linux.se> - alpha testing of @@ -17,10 +17,10 @@ * timings support * * The code framework is a modification of vfb.c by Geert Uytterhoeven. - * DotClock and PLL calculations are partly based on i810_driver.c + * DotClock and PLL calculations are partly based on i810_driver.c * in xfree86 v4.0.3 by Precision Insight. - * Watermark calculation and tables are based on i810_wmark.c - * in xfre86 v4.0.3 by Precision Insight. Slight modifications + * Watermark calculation and tables are based on i810_wmark.c + * in xfre86 v4.0.3 by Precision Insight. Slight modifications * only to allow for integer operations instead of floating point. * * This file is subject to the terms and conditions of the GNU General Public @@ -28,6 +28,7 @@ * more details. */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -204,8 +205,8 @@ static void i810_dram_off(u8 __iomem *mmio, u8 mode) * @mode: protect/unprotect * * DESCRIPTION: - * The IBM VGA standard allows protection of certain VGA registers. - * This will protect or unprotect them. + * The IBM VGA standard allows protection of certain VGA registers. + * This will protect or unprotect them. */ static void i810_protect_regs(u8 __iomem *mmio, int mode) { @@ -215,7 +216,7 @@ static void i810_protect_regs(u8 __iomem *mmio, int mode) reg = i810_readb(CR_DATA_CGA, mmio); reg = (mode == OFF) ? reg & ~0x80 : reg | 0x80; - + i810_writeb(CR_INDEX_CGA, mmio, CR11); i810_writeb(CR_DATA_CGA, mmio, reg); } @@ -225,18 +226,18 @@ static void i810_protect_regs(u8 __iomem *mmio, int mode) * @par: pointer to i810fb_par structure * * DESCRIPTION: - * Loads the P, M, and N registers. + * Loads the P, M, and N registers. */ static void i810_load_pll(struct i810fb_par *par) { u32 tmp1, tmp2; u8 __iomem *mmio = par->mmio_start_virtual; - + tmp1 = par->regs.M | par->regs.N << 16; tmp2 = i810_readl(DCLK_2D, mmio); tmp2 &= ~MN_MASK; i810_writel(DCLK_2D, mmio, tmp1 | tmp2); - + tmp1 = par->regs.P; tmp2 = i810_readl(DCLK_0DS, mmio); tmp2 &= ~(P_OR << 16); @@ -254,7 +255,7 @@ static void i810_load_pll(struct i810fb_par *par) * Load values to VGA registers */ static void i810_load_vga(struct i810fb_par *par) -{ +{ u8 __iomem *mmio = par->mmio_start_virtual; /* interlace */ @@ -327,7 +328,7 @@ static void i810_load_2d(struct i810fb_par *par) u8 tmp8; u8 __iomem *mmio = par->mmio_start_virtual; - i810_writel(FW_BLC, mmio, par->watermark); + i810_writel(FW_BLC, mmio, par->watermark); tmp = i810_readl(PIXCONF, mmio); tmp |= 1 | 1 << 20; i810_writel(PIXCONF, mmio, tmp); @@ -339,7 +340,7 @@ static void i810_load_2d(struct i810fb_par *par) tmp8 |= 2; i810_writeb(GR_INDEX, mmio, GR10); i810_writeb(GR_DATA, mmio, tmp8); -} +} /** * i810_hires - enables high resolution mode @@ -348,7 +349,7 @@ static void i810_load_2d(struct i810fb_par *par) static void i810_hires(u8 __iomem *mmio) { u8 val; - + i810_writeb(CR_INDEX_CGA, mmio, CR80); val = i810_readb(CR_DATA_CGA, mmio); i810_writeb(CR_INDEX_CGA, mmio, CR80); @@ -363,13 +364,13 @@ static void i810_hires(u8 __iomem *mmio) * * DESCRIPTION: * Loads the characters per line - */ + */ static void i810_load_pitch(struct i810fb_par *par) { u32 tmp, pitch; u8 val; u8 __iomem *mmio = par->mmio_start_virtual; - + pitch = par->pitch >> 3; i810_writeb(SR_INDEX, mmio, SR01); val = i810_readb(SR_DATA, mmio); @@ -381,7 +382,7 @@ static void i810_load_pitch(struct i810fb_par *par) tmp = pitch & 0xFF; i810_writeb(CR_INDEX_CGA, mmio, CR13); i810_writeb(CR_DATA_CGA, mmio, (u8) tmp); - + tmp = pitch >> 8; i810_writeb(CR_INDEX_CGA, mmio, CR41); val = i810_readb(CR_DATA_CGA, mmio) & ~0x0F; @@ -414,7 +415,7 @@ static void i810_load_color(struct i810fb_par *par) /** * i810_load_regs - loads all registers for the mode * @par: pointer to i810fb_par structure - * + * * DESCRIPTION: * Loads registers */ @@ -428,7 +429,7 @@ static void i810_load_regs(struct i810fb_par *par) i810_load_pll(par); i810_load_vga(par); i810_load_vgax(par); - i810_dram_off(mmio, ON); + i810_dram_off(mmio, ON); i810_load_2d(par); i810_hires(mmio); i810_screen_off(mmio, ON); @@ -443,7 +444,7 @@ static void i810_write_dac(u8 regno, u8 red, u8 green, u8 blue, i810_writeb(CLUT_INDEX_WRITE, mmio, regno); i810_writeb(CLUT_DATA, mmio, red); i810_writeb(CLUT_DATA, mmio, green); - i810_writeb(CLUT_DATA, mmio, blue); + i810_writeb(CLUT_DATA, mmio, blue); } static void i810_read_dac(u8 regno, u8 *red, u8 *green, u8 *blue, @@ -456,13 +457,13 @@ static void i810_read_dac(u8 regno, u8 *red, u8 *green, u8 *blue, } /************************************************************ - * VGA State Restore * + * VGA State Restore * ************************************************************/ static void i810_restore_pll(struct i810fb_par *par) { u32 tmp1, tmp2; u8 __iomem *mmio = par->mmio_start_virtual; - + tmp1 = par->hw_state.dclk_2d; tmp2 = i810_readl(DCLK_2D, mmio); tmp1 &= ~MN_MASK; @@ -494,7 +495,7 @@ static void i810_restore_vgax(struct i810fb_par *par) { u8 i, j; u8 __iomem *mmio = par->mmio_start_virtual; - + for (i = 0; i < 4; i++) { i810_writeb(CR_INDEX_CGA, mmio, CR30+i); i810_writeb(CR_DATA_CGA, mmio, *(&(par->hw_state.cr30) + i)); @@ -528,7 +529,7 @@ static void i810_restore_vga(struct i810fb_par *par) { u8 i; u8 __iomem *mmio = par->mmio_start_virtual; - + for (i = 0; i < 10; i++) { i810_writeb(CR_INDEX_CGA, mmio, CR00 + i); i810_writeb(CR_DATA_CGA, mmio, *((&par->hw_state.cr00) + i)); @@ -559,10 +560,10 @@ static void i810_restore_2d(struct i810fb_par *par) u8 __iomem *mmio = par->mmio_start_virtual; tmp_word = i810_readw(BLTCNTL, mmio); - tmp_word &= ~(3 << 4); + tmp_word &= ~(3 << 4); tmp_word |= par->hw_state.bltcntl; i810_writew(BLTCNTL, mmio, tmp_word); - + i810_dram_off(mmio, OFF); i810_writel(PIXCONF, mmio, par->hw_state.pixconf); i810_dram_off(mmio, ON); @@ -577,7 +578,7 @@ static void i810_restore_2d(struct i810fb_par *par) tmp_long |= par->hw_state.fw_blc; i810_writel(FW_BLC, mmio, tmp_long); - i810_writel(HWS_PGA, mmio, par->hw_state.hws_pga); + i810_writel(HWS_PGA, mmio, par->hw_state.hws_pga); i810_writew(IER, mmio, par->hw_state.ier); i810_writew(IMR, mmio, par->hw_state.imr); i810_writel(DPLYSTAS, mmio, par->hw_state.dplystas); @@ -621,7 +622,7 @@ static void i810_save_vgax(struct i810fb_par *par) i810_writeb(CR_INDEX_CGA, mmio, CR41); par->hw_state.cr41 = i810_readb(CR_DATA_CGA, mmio); i810_writeb(CR_INDEX_CGA, mmio, CR70); - par->hw_state.cr70 = i810_readb(CR_DATA_CGA, mmio); + par->hw_state.cr70 = i810_readb(CR_DATA_CGA, mmio); par->hw_state.msr = i810_readb(MSR_READ, mmio); i810_writeb(CR_INDEX_CGA, mmio, CR80); par->hw_state.cr80 = i810_readb(CR_DATA_CGA, mmio); @@ -654,8 +655,8 @@ static void i810_save_2d(struct i810fb_par *par) par->hw_state.pixconf = i810_readl(PIXCONF, mmio); par->hw_state.fw_blc = i810_readl(FW_BLC, mmio); par->hw_state.bltcntl = i810_readw(BLTCNTL, mmio); - par->hw_state.hwstam = i810_readw(HWSTAM, mmio); - par->hw_state.hws_pga = i810_readl(HWS_PGA, mmio); + par->hw_state.hwstam = i810_readw(HWSTAM, mmio); + par->hw_state.hws_pga = i810_readl(HWS_PGA, mmio); par->hw_state.ier = i810_readw(IER, mmio); par->hw_state.imr = i810_readw(IMR, mmio); par->hw_state.dplystas = i810_readl(DPLYSTAS, mmio); @@ -669,7 +670,7 @@ static void i810_save_vga_state(struct i810fb_par *par) } /************************************************************ - * Helpers * + * Helpers * ************************************************************/ /** * get_line_length - calculates buffer pitch in bytes @@ -678,12 +679,12 @@ static void i810_save_vga_state(struct i810fb_par *par) * @bpp: bits per pixel * * DESCRIPTION: - * Calculates buffer pitch in bytes. + * Calculates buffer pitch in bytes. */ static u32 get_line_length(struct i810fb_par *par, int xres_virtual, int bpp) { u32 length; - + length = xres_virtual*bpp; length = (length+31)&-32; length >>= 3; @@ -716,17 +717,17 @@ static void i810_calc_dclk(u32 freq, u32 *m, u32 *n, u32 *p) n_target_max = 30; /* - * find P such that target freq is 16x reference freq (Hz). + * find P such that target freq is 16x reference freq (Hz). */ p_divisor = 1; p_target = 0; - while(!((1000000 * p_divisor)/(16 * 24 * target_freq)) && + while(!((1000000 * p_divisor)/(16 * 24 * target_freq)) && p_divisor <= 32) { p_divisor <<= 1; p_target++; } - n_reg = m_reg = n_target = 3; + n_reg = m_reg = n_target = 3; while (diff_min && mod_min && (n_target < n_target_max)) { f_out = (p_divisor * n_reg * 1000000)/(4 * 24 * m_reg); mod = (p_divisor * n_reg * 1000000) % (4 * 24 * m_reg); @@ -744,14 +745,14 @@ static void i810_calc_dclk(u32 freq, u32 *m, u32 *n, u32 *p) diff_min = diff; n_best = n_target; m_best = m_target; - } + } if (!diff && mod_min > mod) { mod_min = mod; n_best = n_target; m_best = m_target; } - } + } if (m) *m = (m_best - 2) & 0x3FF; if (n) *n = (n_best - 2) & 0x3FF; if (p) *p = (p_target << 4); @@ -772,7 +773,7 @@ static void i810_calc_dclk(u32 freq, u32 *m, u32 *n, u32 *p) static void i810_enable_cursor(u8 __iomem *mmio, int mode) { u32 temp; - + temp = i810_readl(PIXCONF, mmio); temp = (mode == ON) ? temp | CURSOR_ENABLE_MASK : temp & ~CURSOR_ENABLE_MASK; @@ -786,10 +787,10 @@ static void i810_reset_cursor_image(struct i810fb_par *par) int i, j; for (i = 64; i--; ) { - for (j = 0; j < 8; j++) { - i810_writeb(j, addr, 0xff); - i810_writeb(j+8, addr, 0x00); - } + for (j = 0; j < 8; j++) { + i810_writeb(j, addr, 0xff); + i810_writeb(j+8, addr, 0x00); + } addr +=16; } } @@ -800,9 +801,9 @@ static void i810_load_cursor_image(int width, int height, u8 *data, u8 __iomem *addr = par->cursor_heap.virtual; int i, j, w = width/8; int mod = width % 8, t_mask, d_mask; - + t_mask = 0xff >> mod; - d_mask = ~(0xff >> mod); + d_mask = ~(0xff >> mod); for (i = height; i--; ) { for (j = 0; j < w; j++) { i810_writeb(j+0, addr, 0x00); @@ -854,7 +855,7 @@ static void i810_init_cursor(struct i810fb_par *par) i810_enable_cursor(mmio, OFF); i810_writel(CURBASE, mmio, par->cursor_heap.physical); i810_writew(CURCNTR, mmio, COORD_ACTIVE | CURSOR_MODE_64_XOR); -} +} /********************************************************************* * Framebuffer hook helpers * @@ -873,7 +874,7 @@ static void i810_round_off(struct fb_var_screeninfo *var) u32 xres, yres, vxres, vyres; /* - * Presently supports only these configurations + * Presently supports only these configurations */ xres = var->xres; @@ -883,20 +884,20 @@ static void i810_round_off(struct fb_var_screeninfo *var) var->bits_per_pixel += 7; var->bits_per_pixel &= ~7; - + if (var->bits_per_pixel < 8) var->bits_per_pixel = 8; - if (var->bits_per_pixel > 32) + if (var->bits_per_pixel > 32) var->bits_per_pixel = 32; round_off_xres(&xres); if (xres < 40) xres = 40; - if (xres > 2048) + if (xres > 2048) xres = 2048; xres = (xres + 7) & ~7; - if (vxres < xres) + if (vxres < xres) vxres = xres; round_off_yres(&xres, &yres); @@ -905,7 +906,7 @@ static void i810_round_off(struct fb_var_screeninfo *var) if (yres >= 2048) yres = 2048; - if (vyres < yres) + if (vyres < yres) vyres = yres; if (var->bits_per_pixel == 32) @@ -917,30 +918,30 @@ static void i810_round_off(struct fb_var_screeninfo *var) var->hsync_len = (var->hsync_len + 4) & ~7; if (var->vmode & FB_VMODE_INTERLACED) { - if (!((yres + var->upper_margin + var->vsync_len + + if (!((yres + var->upper_margin + var->vsync_len + var->lower_margin) & 1)) var->upper_margin++; } - + var->xres = xres; var->yres = yres; var->xres_virtual = vxres; var->yres_virtual = vyres; -} +} /** * set_color_bitfields - sets rgba fields * @var: pointer to fb_var_screeninfo * * DESCRIPTION: - * The length, offset and ordering for each color field - * (red, green, blue) will be set as specified + * The length, offset and ordering for each color field + * (red, green, blue) will be set as specified * by the hardware - */ + */ static void set_color_bitfields(struct fb_var_screeninfo *var) { switch (var->bits_per_pixel) { - case 8: + case 8: var->red.offset = 0; var->red.length = 8; var->green.offset = 0; @@ -984,11 +985,11 @@ static void set_color_bitfields(struct fb_var_screeninfo *var) * @info: pointer to fb_info * * DESCRIPTION: - * This will check if the framebuffer size is sufficient - * for the current mode and if the user's monitor has the + * This will check if the framebuffer size is sufficient + * for the current mode and if the user's monitor has the * required specifications to display the current mode. */ -static int i810_check_params(struct fb_var_screeninfo *var, +static int i810_check_params(struct fb_var_screeninfo *var, struct fb_info *info) { struct i810fb_par *par = info->par; @@ -1007,14 +1008,14 @@ static int i810_check_params(struct fb_var_screeninfo *var, vyres = info->var.yres; vxres = par->fb.size/vyres; vxres /= var->bits_per_pixel >> 3; - line_length = get_line_length(par, vxres, + line_length = get_line_length(par, vxres, var->bits_per_pixel); vidmem = line_length * info->var.yres; if (vxres < var->xres) { printk("i810fb: required video memory, " "%d bytes, for %dx%d-%d (virtual) " - "is out of range\n", - vidmem, vxres, vyres, + "is out of range\n", + vidmem, vxres, vyres, var->bits_per_pixel); return -ENOMEM; } @@ -1074,7 +1075,7 @@ static int i810_check_params(struct fb_var_screeninfo *var, } return retval; -} +} /** * encode_fix - fill up fb_fix_screeninfo structure @@ -1131,9 +1132,9 @@ static int encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info) * * DESCRIPTION: * Based on the contents of @var, @par will be dynamically filled up. - * @par contains all information necessary to modify the hardware. + * @par contains all information necessary to modify the hardware. */ -static void decode_var(const struct fb_var_screeninfo *var, +static void decode_var(const struct fb_var_screeninfo *var, struct i810fb_par *par) { u32 xres, yres, vxres, vyres; @@ -1175,13 +1176,13 @@ static void decode_var(const struct fb_var_screeninfo *var, if (var->nonstd && var->bits_per_pixel != 8) par->pixconf |= 1 << 27; - i810_calc_dclk(var->pixclock, &par->regs.M, + i810_calc_dclk(var->pixclock, &par->regs.M, &par->regs.N, &par->regs.P); i810fb_encode_registers(var, par, xres, yres); par->watermark = i810_get_watermark(var, par); par->pitch = get_line_length(par, vxres, var->bits_per_pixel); -} +} /** * i810fb_getcolreg - gets red, green and blue values of the hardware DAC @@ -1196,7 +1197,7 @@ static void decode_var(const struct fb_var_screeninfo *var, * Gets the red, green and blue values of the hardware DAC as pointed by @regno * and writes them to @red, @green and @blue respectively */ -static int i810fb_getcolreg(u8 regno, u8 *red, u8 *green, u8 *blue, +static int i810fb_getcolreg(u8 regno, u8 *red, u8 *green, u8 *blue, u8 *transp, struct fb_info *info) { struct i810fb_par *par = info->par; @@ -1212,18 +1213,18 @@ static int i810fb_getcolreg(u8 regno, u8 *red, u8 *green, u8 *blue, temp = i810_readb(PIXCONF1, mmio); i810_writeb(PIXCONF1, mmio, temp & ~EXTENDED_PALETTE); - if (info->fix.visual == FB_VISUAL_DIRECTCOLOR && - info->var.green.length == 5) + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR && + info->var.green.length == 5) i810_read_dac(regno * 8, red, green, blue, mmio); - else if (info->fix.visual == FB_VISUAL_DIRECTCOLOR && + else if (info->fix.visual == FB_VISUAL_DIRECTCOLOR && info->var.green.length == 6) { u8 tmp; i810_read_dac(regno * 8, red, &tmp, blue, mmio); i810_read_dac(regno * 4, &tmp, green, &tmp, mmio); } - else + else i810_read_dac(regno, red, green, blue, mmio); *transp = 0; @@ -1232,7 +1233,7 @@ static int i810fb_getcolreg(u8 regno, u8 *red, u8 *green, u8 *blue, return 0; } -/****************************************************************** +/****************************************************************** * Framebuffer device-specific hooks * ******************************************************************/ @@ -1252,7 +1253,7 @@ static int i810fb_open(struct fb_info *info, int user) par->use_count++; mutex_unlock(&par->open_lock); - + return 0; } @@ -1273,13 +1274,13 @@ static int i810fb_release(struct fb_info *info, int user) par->use_count--; mutex_unlock(&par->open_lock); - + return 0; } -static int i810fb_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, +static int i810fb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info) { struct i810fb_par *par = info->par; @@ -1302,24 +1303,24 @@ static int i810fb_setcolreg(unsigned regno, unsigned red, unsigned green, temp = i810_readb(PIXCONF1, mmio); i810_writeb(PIXCONF1, mmio, temp & ~EXTENDED_PALETTE); - if (info->fix.visual == FB_VISUAL_DIRECTCOLOR && + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR && info->var.green.length == 5) { - for (i = 0; i < 8; i++) - i810_write_dac((u8) (regno * 8) + i, (u8) red, + for (i = 0; i < 8; i++) + i810_write_dac((u8) (regno * 8) + i, (u8) red, (u8) green, (u8) blue, mmio); - } else if (info->fix.visual == FB_VISUAL_DIRECTCOLOR && + } else if (info->fix.visual == FB_VISUAL_DIRECTCOLOR && info->var.green.length == 6) { u8 r, g, b; if (regno < 32) { - for (i = 0; i < 8; i++) + for (i = 0; i < 8; i++) i810_write_dac((u8) (regno * 8) + i, - (u8) red, (u8) green, + (u8) red, (u8) green, (u8) blue, mmio); } i810_read_dac((u8) (regno*4), &r, &g, &b, mmio); - for (i = 0; i < 4; i++) - i810_write_dac((u8) (regno*4) + i, r, (u8) green, + for (i = 0; i < 4; i++) + i810_write_dac((u8) (regno*4) + i, r, (u8) green, b, mmio); } else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) { i810_write_dac((u8) regno, (u8) red, (u8) green, @@ -1330,20 +1331,20 @@ static int i810fb_setcolreg(unsigned regno, unsigned red, unsigned green, if (regno < 16) { switch (info->var.bits_per_pixel) { - case 16: + case 16: if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) { - if (info->var.green.length == 5) - ((u32 *)info->pseudo_palette)[regno] = + if (info->var.green.length == 5) + ((u32 *)info->pseudo_palette)[regno] = (regno << 10) | (regno << 5) | regno; else - ((u32 *)info->pseudo_palette)[regno] = + ((u32 *)info->pseudo_palette)[regno] = (regno << 11) | (regno << 5) | regno; } else { if (info->var.green.length == 5) { /* RGB 555 */ - ((u32 *)info->pseudo_palette)[regno] = + ((u32 *)info->pseudo_palette)[regno] = ((red & 0xf800) >> 1) | ((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11); @@ -1358,12 +1359,12 @@ static int i810fb_setcolreg(unsigned regno, unsigned red, unsigned green, break; case 24: /* RGB 888 */ case 32: /* RGBA 8888 */ - if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) - ((u32 *)info->pseudo_palette)[regno] = + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) + ((u32 *)info->pseudo_palette)[regno] = (regno << 16) | (regno << 8) | regno; - else - ((u32 *)info->pseudo_palette)[regno] = + else + ((u32 *)info->pseudo_palette)[regno] = ((red & 0xff00) << 8) | (green & 0xff00) | ((blue & 0xff00) >> 8); @@ -1373,13 +1374,13 @@ static int i810fb_setcolreg(unsigned regno, unsigned red, unsigned green, return 0; } -static int i810fb_pan_display(struct fb_var_screeninfo *var, +static int i810fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { struct i810fb_par *par = info->par; u32 total; - - total = var->xoffset * par->depth + + + total = var->xoffset * par->depth + var->yoffset * info->fix.line_length; i810fb_load_front(total, info); @@ -1391,7 +1392,7 @@ static int i810fb_blank (int blank_mode, struct fb_info *info) struct i810fb_par *par = info->par; u8 __iomem *mmio = par->mmio_start_virtual; int mode = 0, pwr, scr_off = 0; - + pwr = i810_readl(PWR_CLKC, mmio); switch (blank_mode) { @@ -1421,7 +1422,7 @@ static int i810fb_blank (int blank_mode, struct fb_info *info) scr_off = OFF; break; default: - return -EINVAL; + return -EINVAL; } i810_screen_off(mmio, scr_off); @@ -1452,7 +1453,7 @@ static int i810fb_set_par(struct fb_info *info) return 0; } -static int i810fb_check_var(struct fb_var_screeninfo *var, +static int i810fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { int err; @@ -1550,7 +1551,7 @@ static const struct fb_ops i810fb_ops = { .fb_set_par = i810fb_set_par, .fb_setcolreg = i810fb_setcolreg, .fb_blank = i810fb_blank, - .fb_pan_display = i810fb_pan_display, + .fb_pan_display = i810fb_pan_display, .fb_fillrect = i810fb_fillrect, .fb_copyarea = i810fb_copyarea, .fb_imageblit = i810fb_imageblit, @@ -1593,7 +1594,7 @@ static int i810fb_suspend(struct pci_dev *dev, pm_message_t mesg) return 0; } -static int i810fb_resume(struct pci_dev *dev) +static int i810fb_resume(struct pci_dev *dev) { struct fb_info *info = pci_get_drvdata(dev); struct i810fb_par *par = info->par; @@ -1628,14 +1629,14 @@ fail: /*********************************************************************** * AGP resource allocation * ***********************************************************************/ - + static void i810_fix_pointers(struct i810fb_par *par) { par->fb.physical = par->aperture.physical+(par->fb.offset << 12); par->fb.virtual = par->aperture.virtual+(par->fb.offset << 12); - par->iring.physical = par->aperture.physical + + par->iring.physical = par->aperture.physical + (par->iring.offset << 12); - par->iring.virtual = par->aperture.virtual + + par->iring.virtual = par->aperture.virtual + (par->iring.offset << 12); par->cursor_heap.virtual = par->aperture.virtual+ (par->cursor_heap.offset << 12); @@ -1666,7 +1667,7 @@ static int i810_alloc_agp_mem(struct fb_info *info) struct i810fb_par *par = info->par; int size; struct agp_bridge_data *bridge; - + i810_fix_offsets(par); size = par->fb.size + par->iring.size; @@ -1674,7 +1675,7 @@ static int i810_alloc_agp_mem(struct fb_info *info) printk("i810fb_alloc_fbmem: cannot acquire agpgart\n"); return -ENODEV; } - if (!(par->i810_gtt.i810_fb_memory = + if (!(par->i810_gtt.i810_fb_memory = agp_allocate_memory(bridge, size >> 12, AGP_NORMAL_MEMORY))) { printk("i810fb_alloc_fbmem: can't allocate framebuffer " "memory\n"); @@ -1686,9 +1687,9 @@ static int i810_alloc_agp_mem(struct fb_info *info) printk("i810fb_alloc_fbmem: can't bind framebuffer memory\n"); agp_backend_release(bridge); return -EBUSY; - } - - if (!(par->i810_gtt.i810_cursor_memory = + } + + if (!(par->i810_gtt.i810_cursor_memory = agp_allocate_memory(bridge, par->cursor_heap.size >> 12, AGP_PHYSICAL_MEMORY))) { printk("i810fb_alloc_cursormem: can't allocate " @@ -1701,7 +1702,7 @@ static int i810_alloc_agp_mem(struct fb_info *info) printk("i810fb_alloc_cursormem: cannot bind cursor memory\n"); agp_backend_release(bridge); return -EBUSY; - } + } par->cursor_heap.physical = par->i810_gtt.i810_cursor_memory->physical; @@ -1712,8 +1713,8 @@ static int i810_alloc_agp_mem(struct fb_info *info) return 0; } -/*************************************************************** - * Initialization * +/*************************************************************** + * Initialization * ***************************************************************/ /** @@ -1728,7 +1729,7 @@ static void i810_init_monspecs(struct fb_info *info) { if (!hsync1) hsync1 = HFMIN; - if (!hsync2) + if (!hsync2) hsync2 = HFMAX; if (!info->monspecs.hfmax) info->monspecs.hfmax = hsync2; @@ -1739,7 +1740,7 @@ static void i810_init_monspecs(struct fb_info *info) if (!vsync1) vsync1 = VFMIN; - if (!vsync2) + if (!vsync2) vsync2 = VFMAX; if (IS_DVT && vsync1 < 60) vsync1 = 60; @@ -1747,7 +1748,7 @@ static void i810_init_monspecs(struct fb_info *info) info->monspecs.vfmax = vsync2; if (!info->monspecs.vfmin) info->monspecs.vfmin = vsync1; - if (vsync2 < vsync1) + if (vsync2 < vsync1) info->monspecs.vfmin = vsync2; } @@ -1760,27 +1761,27 @@ static void i810_init_defaults(struct i810fb_par *par, struct fb_info *info) { mutex_init(&par->open_lock); - if (voffset) + if (voffset) v_offset_default = voffset; else if (par->aperture.size > 32 * 1024 * 1024) v_offset_default = 16; else v_offset_default = 8; - if (!vram) + if (!vram) vram = 1; - if (accel) + if (accel) par->dev_flags |= HAS_ACCELERATION; - if (sync) + if (sync) par->dev_flags |= ALWAYS_SYNC; par->ddc_num = (ddc3 ? 3 : 2); if (bpp < 8) bpp = 8; - + par->i810fb_ops = i810fb_ops; if (xres) @@ -1793,7 +1794,7 @@ static void i810_init_defaults(struct i810fb_par *par, struct fb_info *info) else info->var.yres = 480; - if (!vyres) + if (!vyres) vyres = (vram << 20)/(info->var.xres*bpp >> 3); info->var.yres_virtual = vyres; @@ -1802,12 +1803,12 @@ static void i810_init_defaults(struct i810fb_par *par, struct fb_info *info) if (dcolor) info->var.nonstd = 1; - if (par->dev_flags & HAS_ACCELERATION) + if (par->dev_flags & HAS_ACCELERATION) info->var.accel_flags = 1; i810_init_monspecs(info); } - + /** * i810_init_device - initialize device * @par: pointer to i810fb_par structure @@ -1840,9 +1841,9 @@ static int i810_allocate_pci_resource(struct i810fb_par *par, { int err; - if ((err = pci_enable_device(par->dev))) { + if ((err = pci_enable_device(par->dev))) { printk("i810fb_init: cannot enable device\n"); - return err; + return err; } par->res_flags |= PCI_DEVICE_ENABLED; @@ -1860,8 +1861,8 @@ static int i810_allocate_pci_resource(struct i810fb_par *par, return -ENOMEM; } - if (!request_mem_region(par->aperture.physical, - par->aperture.size, + if (!request_mem_region(par->aperture.physical, + par->aperture.size, i810_pci_list[entry->driver_data])) { printk("i810fb_init: cannot request framebuffer region\n"); return -ENODEV; @@ -1874,16 +1875,16 @@ static int i810_allocate_pci_resource(struct i810fb_par *par, printk("i810fb_init: cannot remap framebuffer region\n"); return -ENODEV; } - - if (!request_mem_region(par->mmio_start_phys, - MMIO_SIZE, + + if (!request_mem_region(par->mmio_start_phys, + MMIO_SIZE, i810_pci_list[entry->driver_data])) { printk("i810fb_init: cannot request mmio region\n"); return -ENODEV; } par->res_flags |= MMIO_REQ; - par->mmio_start_virtual = ioremap(par->mmio_start_phys, + par->mmio_start_virtual = ioremap(par->mmio_start_phys, MMIO_SIZE); if (!par->mmio_start_virtual) { printk("i810fb_init: cannot remap mmio region\n"); @@ -1963,7 +1964,7 @@ static int i810fb_setup(char *options) if (!options || !*options) return 0; - + while ((this_opt = strsep(&options, ",")) != NULL) { if (!strncmp(this_opt, "mtrr", 4)) mtrr = true; @@ -1987,13 +1988,13 @@ static int i810fb_setup(char *options) bpp = simple_strtoul(this_opt+4, NULL, 0); else if (!strncmp(this_opt, "hsync1:", 7)) { hsync1 = simple_strtoul(this_opt+7, &suffix, 0); - if (strncmp(suffix, "H", 1)) + if (strncmp(suffix, "H", 1)) hsync1 *= 1000; } else if (!strncmp(this_opt, "hsync2:", 7)) { hsync2 = simple_strtoul(this_opt+7, &suffix, 0); - if (strncmp(suffix, "H", 1)) + if (strncmp(suffix, "H", 1)) hsync2 *= 1000; - } else if (!strncmp(this_opt, "vsync1:", 7)) + } else if (!strncmp(this_opt, "vsync1:", 7)) vsync1 = simple_strtoul(this_opt+7, NULL, 0); else if (!strncmp(this_opt, "vsync2:", 7)) vsync2 = simple_strtoul(this_opt+7, NULL, 0); @@ -2016,6 +2017,10 @@ static int i810fb_init_pci(struct pci_dev *dev, struct fb_videomode mode; int err = -1, vfreq, hfreq, pixclock; + err = aperture_remove_conflicting_pci_devices(dev, "i810fb"); + if (err) + return err; + info = framebuffer_alloc(sizeof(struct i810fb_par), &dev->dev); if (!info) return -ENOMEM; @@ -2044,7 +2049,7 @@ static int i810fb_init_pci(struct pci_dev *dev, return err; } - i810_init_device(par); + i810_init_device(par); info->screen_base = par->fb.virtual; info->fbops = &par->i810fb_ops; @@ -2064,21 +2069,21 @@ static int i810fb_init_pci(struct pci_dev *dev, err = register_framebuffer(info); if (err < 0) { - i810fb_release_resource(info, par); + i810fb_release_resource(info, par); printk("i810fb_init: cannot register framebuffer device\n"); - return err; - } + return err; + } pci_set_drvdata(dev, info); pixclock = 1000000000/(info->var.pixclock); pixclock *= 1000; - hfreq = pixclock/(info->var.xres + info->var.left_margin + + hfreq = pixclock/(info->var.xres + info->var.left_margin + info->var.hsync_len + info->var.right_margin); vfreq = hfreq/(info->var.yres + info->var.upper_margin + info->var.vsync_len + info->var.lower_margin); printk("I810FB: fb%d : %s v%d.%d.%d%s\n" - "I810FB: Video RAM : %dK\n" + "I810FB: Video RAM : %dK\n" "I810FB: Monitor : H: %d-%d KHz V: %d-%d Hz\n" "I810FB: Mode : %dx%d-%dbpp@%dHz\n", info->node, @@ -2086,7 +2091,7 @@ static int i810fb_init_pci(struct pci_dev *dev, VERSION_MAJOR, VERSION_MINOR, VERSION_TEENIE, BRANCH_VERSION, (int) par->fb.size>>10, info->monspecs.hfmin/1000, info->monspecs.hfmax/1000, info->monspecs.vfmin, - info->monspecs.vfmax, info->var.xres, + info->monspecs.vfmax, info->var.xres, info->var.yres, info->var.bits_per_pixel, vfreq); return 0; } @@ -2095,7 +2100,7 @@ static int i810fb_init_pci(struct pci_dev *dev, * De-initialization * ***************************************************************/ -static void i810fb_release_resource(struct fb_info *info, +static void i810fb_release_resource(struct fb_info *info, struct i810fb_par *par) { struct gtt_data *gtt = &par->i810_gtt; @@ -2128,10 +2133,10 @@ static void i810fb_remove_pci(struct pci_dev *dev) struct fb_info *info = pci_get_drvdata(dev); struct i810fb_par *par = info->par; - unregister_framebuffer(info); + unregister_framebuffer(info); i810fb_release_resource(info, par); printk("cleanup_module: unloaded i810 framebuffer device\n"); -} +} #ifndef MODULE static int i810fb_init(void) @@ -2144,7 +2149,7 @@ static int i810fb_init(void) return pci_register_driver(&i810fb_driver); } -#endif +#endif /********************************************************************* * Modularization * @@ -2161,7 +2166,7 @@ static int i810fb_init(void) } module_param(vram, int, 0); -MODULE_PARM_DESC(vram, "System RAM to allocate to framebuffer in MiB" +MODULE_PARM_DESC(vram, "System RAM to allocate to framebuffer in MiB" " (default=4)"); module_param(voffset, int, 0); MODULE_PARM_DESC(voffset, "at what offset to place start of framebuffer " @@ -2186,7 +2191,7 @@ module_param(vsync1, int, 0); MODULE_PARM_DESC(vsync1, "Minimum vertical frequency of monitor in Hz" " (default = 50)"); module_param(vsync2, int, 0); -MODULE_PARM_DESC(vsync2, "Maximum vertical frequency of monitor in Hz" +MODULE_PARM_DESC(vsync2, "Maximum vertical frequency of monitor in Hz" " (default = 60)"); module_param(accel, bool, 0); MODULE_PARM_DESC(accel, "Use Acceleration (BLIT) engine (default = 0)"); @@ -2208,7 +2213,7 @@ MODULE_PARM_DESC(mode_option, "Specify initial video mode"); MODULE_AUTHOR("Tony A. Daplas"); MODULE_DESCRIPTION("Framebuffer device for the Intel 810/815 and" " compatible cards"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL"); static void __exit i810fb_exit(void) { diff --git a/drivers/video/fbdev/imsttfb.c b/drivers/video/fbdev/imsttfb.c index 16f272a50811..d7edb9c5d3a3 100644 --- a/drivers/video/fbdev/imsttfb.c +++ b/drivers/video/fbdev/imsttfb.c @@ -16,6 +16,7 @@ * more details. */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -86,7 +87,7 @@ enum { SSTATUS = 36, /* 0x90 */ PRC = 37, /* 0x94 */ -#if 0 +#if 0 /* PCI Registers */ DVID = 0x00000000L, SC = 0x00000004L, @@ -103,8 +104,8 @@ enum { PDATA = 0x04, PPMASK = 0x08, PADDRR = 0x0c, - PIDXLO = 0x10, - PIDXHI = 0x14, + PIDXLO = 0x10, + PIDXHI = 0x14, PIDXDATA= 0x18, PIDXCTL = 0x1c }; @@ -131,7 +132,7 @@ enum { SYSCLKC = 0x18, /* () System Clock C */ /* * Dot clock rate is 20MHz * (m + 1) / ((n + 1) * (p ? 2 * p : 1) - * c is charge pump bias which depends on the VCO frequency + * c is charge pump bias which depends on the VCO frequency */ PIXM0 = 0x20, /* () Pixel M 0 */ PIXN0 = 0x21, /* () Pixel N 0 */ @@ -320,7 +321,7 @@ struct imstt_par { __u32 ramdac; __u32 palette[16]; }; - + enum { IBM = 0, TVP = 1 @@ -373,7 +374,7 @@ static struct imstt_regvals tvp_reg_init_17 = { static struct imstt_regvals tvp_reg_init_18 = { 1152, - 0x0009, 0x0011, 0x059, 0x5b, 0x0003, 0x0031, 0x0397, 0x039a, 0x0000, + 0x0009, 0x0011, 0x059, 0x5b, 0x0003, 0x0031, 0x0397, 0x039a, 0x0000, 0xfd, 0x3a, 0xf1, { 0x39, 0x38, 0x38 }, { 0xf3, 0xf3, 0xf2 } }; @@ -856,10 +857,10 @@ imsttfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) } static int -imsttfb_set_par(struct fb_info *info) +imsttfb_set_par(struct fb_info *info) { struct imstt_par *par = info->par; - + if (!compute_imstt_regvals(par, info->var.xres, info->var.yres)) return -EINVAL; @@ -930,7 +931,7 @@ imsttfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) return 0; } -static int +static int imsttfb_blank(int blank, struct fb_info *info) { struct imstt_par *par = info->par; @@ -986,7 +987,7 @@ imsttfb_blank(int blank, struct fb_info *info) static void imsttfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) -{ +{ struct imstt_par *par = info->par; __u32 Bpp, line_pitch, bgc, dx, dy, width, height; @@ -1192,7 +1193,7 @@ imstt_set_cursor(struct imstt_par *par, struct fb_image *d, int on) } } -static int +static int imsttfb_cursor(struct fb_info *info, struct fb_cursor *cursor) { struct imstt_par *par = info->par; @@ -1200,7 +1201,7 @@ imsttfb_cursor(struct fb_info *info, struct fb_cursor *cursor) if (cursor->dest == NULL && cursor->rop == ROP_XOR) return 1; - + imstt_set_cursor(info, cursor, 0); if (flags & FB_CUR_SETPOS) { @@ -1469,8 +1470,13 @@ static int imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct imstt_par *par; struct fb_info *info; struct device_node *dp; - int ret = -ENOMEM; - + int ret; + + ret = aperture_remove_conflicting_pci_devices(pdev, "imsttfb"); + if (ret) + return ret; + ret = -ENOMEM; + dp = pci_device_to_OF_node(pdev); if(dp) printk(KERN_INFO "%s: OF name %pOFn\n",__func__, dp); @@ -1619,7 +1625,7 @@ static int __init imsttfb_init(void) #endif return pci_register_driver(&imsttfb_pci_driver); } - + static void __exit imsttfb_exit(void) { pci_unregister_driver(&imsttfb_pci_driver); diff --git a/drivers/video/fbdev/intelfb/intelfbdrv.c b/drivers/video/fbdev/intelfb/intelfbdrv.c index 5647fca8c49a..d4a2891a9a7a 100644 --- a/drivers/video/fbdev/intelfb/intelfbdrv.c +++ b/drivers/video/fbdev/intelfb/intelfbdrv.c @@ -107,6 +107,7 @@ * Add support for 945GME. (Phil Endecott <spam_from_intelfb@chezphil.org>) */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -483,6 +484,10 @@ static int intelfb_pci_register(struct pci_dev *pdev, DBG_MSG("intelfb_pci_register\n"); + err = aperture_remove_conflicting_pci_devices(pdev, "intelfb"); + if (err) + return err; + num_registered++; if (num_registered != 1) { ERR_MSG("Attempted to register %d devices " diff --git a/drivers/video/fbdev/kyro/fbdev.c b/drivers/video/fbdev/kyro/fbdev.c index d57772f96ad2..b4b93054c520 100644 --- a/drivers/video/fbdev/kyro/fbdev.c +++ b/drivers/video/fbdev/kyro/fbdev.c @@ -9,6 +9,7 @@ * for more details. */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> @@ -676,6 +677,10 @@ static int kyrofb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) unsigned long size; int err; + err = aperture_remove_conflicting_pci_devices(pdev, "kyrofb"); + if (err) + return err; + if ((err = pci_enable_device(pdev))) { printk(KERN_WARNING "kyrofb: Can't enable pdev: %d\n", err); return err; diff --git a/drivers/video/fbdev/matrox/matroxfb_base.c b/drivers/video/fbdev/matrox/matroxfb_base.c index 236521b19daf..3e26346c05a2 100644 --- a/drivers/video/fbdev/matrox/matroxfb_base.c +++ b/drivers/video/fbdev/matrox/matroxfb_base.c @@ -100,6 +100,7 @@ * */ +#include <linux/aperture.h> #include <linux/version.h> #include "matroxfb_base.h" @@ -2044,6 +2045,10 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm u_int32_t cmd; DBG(__func__) + err = aperture_remove_conflicting_pci_devices(pdev, "matroxfb"); + if (err) + return err; + svid = pdev->subsystem_vendor; sid = pdev->subsystem_device; for (b = dev_list; b->vendor; b++) { diff --git a/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c b/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c index a7508f5be343..96800c9c9cd9 100644 --- a/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c +++ b/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c @@ -10,6 +10,7 @@ #undef DEBUG +#include <linux/aperture.h> #include <linux/fb.h> #include <linux/delay.h> #include <linux/uaccess.h> @@ -999,6 +1000,10 @@ static int mb862xx_pci_probe(struct pci_dev *pdev, struct device *dev = &pdev->dev; int ret; + ret = aperture_remove_conflicting_pci_devices(pdev, "mb862xxfb"); + if (ret) + return ret; + ret = pci_enable_device(pdev); if (ret < 0) { dev_err(dev, "Cannot enable PCI device\n"); diff --git a/drivers/video/fbdev/neofb.c b/drivers/video/fbdev/neofb.c index 28d32cbf496b..93a2d2d1abe8 100644 --- a/drivers/video/fbdev/neofb.c +++ b/drivers/video/fbdev/neofb.c @@ -23,9 +23,9 @@ * * 0.3.3 * - Porting over to new fbdev api. (jsimmons) - * + * * 0.3.2 - * - got rid of all floating point (dok) + * - got rid of all floating point (dok) * * 0.3.1 * - added module license (dok) @@ -54,6 +54,7 @@ * */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -1154,14 +1155,14 @@ static int neofb_set_par(struct fb_info *info) switch (info->fix.accel) { case FB_ACCEL_NEOMAGIC_NM2200: - case FB_ACCEL_NEOMAGIC_NM2230: - case FB_ACCEL_NEOMAGIC_NM2360: - case FB_ACCEL_NEOMAGIC_NM2380: + case FB_ACCEL_NEOMAGIC_NM2230: + case FB_ACCEL_NEOMAGIC_NM2360: + case FB_ACCEL_NEOMAGIC_NM2380: neo2200_accel_init(info, &info->var); break; default: break; - } + } return 0; } @@ -1493,15 +1494,15 @@ neofb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { switch (info->fix.accel) { case FB_ACCEL_NEOMAGIC_NM2200: - case FB_ACCEL_NEOMAGIC_NM2230: - case FB_ACCEL_NEOMAGIC_NM2360: + case FB_ACCEL_NEOMAGIC_NM2230: + case FB_ACCEL_NEOMAGIC_NM2360: case FB_ACCEL_NEOMAGIC_NM2380: neo2200_fillrect(info, rect); break; default: cfb_fillrect(info, rect); break; - } + } } static void @@ -1509,15 +1510,15 @@ neofb_copyarea(struct fb_info *info, const struct fb_copyarea *area) { switch (info->fix.accel) { case FB_ACCEL_NEOMAGIC_NM2200: - case FB_ACCEL_NEOMAGIC_NM2230: - case FB_ACCEL_NEOMAGIC_NM2360: - case FB_ACCEL_NEOMAGIC_NM2380: + case FB_ACCEL_NEOMAGIC_NM2230: + case FB_ACCEL_NEOMAGIC_NM2360: + case FB_ACCEL_NEOMAGIC_NM2380: neo2200_copyarea(info, area); break; default: cfb_copyarea(info, area); break; - } + } } static void @@ -1536,20 +1537,20 @@ neofb_imageblit(struct fb_info *info, const struct fb_image *image) } } -static int +static int neofb_sync(struct fb_info *info) { switch (info->fix.accel) { case FB_ACCEL_NEOMAGIC_NM2200: - case FB_ACCEL_NEOMAGIC_NM2230: - case FB_ACCEL_NEOMAGIC_NM2360: - case FB_ACCEL_NEOMAGIC_NM2380: + case FB_ACCEL_NEOMAGIC_NM2230: + case FB_ACCEL_NEOMAGIC_NM2360: + case FB_ACCEL_NEOMAGIC_NM2380: neo2200_sync(info); break; default: break; } - return 0; + return 0; } /* @@ -2029,6 +2030,10 @@ static int neofb_probe(struct pci_dev *dev, const struct pci_device_id *id) DBG("neofb_probe"); + err = aperture_remove_conflicting_pci_devices(dev, "neofb"); + if (err) + return err; + err = pci_enable_device(dev); if (err) return err; diff --git a/drivers/video/fbdev/nvidia/nvidia.c b/drivers/video/fbdev/nvidia/nvidia.c index a372a183c1f0..329e2e8133c6 100644 --- a/drivers/video/fbdev/nvidia/nvidia.c +++ b/drivers/video/fbdev/nvidia/nvidia.c @@ -9,6 +9,7 @@ * */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -1276,11 +1277,15 @@ static int nvidiafb_probe(struct pci_dev *pd, const struct pci_device_id *ent) struct nvidia_par *par; struct fb_info *info; unsigned short cmd; - + int ret; NVTRACE_ENTER(); assert(pd != NULL); + ret = aperture_remove_conflicting_pci_devices(pd, "nvidiafb"); + if (ret) + return ret; + info = framebuffer_alloc(sizeof(struct nvidia_par), &pd->dev); if (!info) diff --git a/drivers/video/fbdev/pm2fb.c b/drivers/video/fbdev/pm2fb.c index d3be2c64f1c0..bc80d8498aeb 100644 --- a/drivers/video/fbdev/pm2fb.c +++ b/drivers/video/fbdev/pm2fb.c @@ -27,6 +27,7 @@ * */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> @@ -1516,6 +1517,10 @@ static int pm2fb_probe(struct pci_dev *pdev, const struct pci_device_id *id) int err; int retval = -ENXIO; + err = aperture_remove_conflicting_pci_devices(pdev, "pm2fb"); + if (err) + return err; + err = pci_enable_device(pdev); if (err) { printk(KERN_WARNING "pm2fb: Can't enable pdev: %d\n", err); diff --git a/drivers/video/fbdev/pm3fb.c b/drivers/video/fbdev/pm3fb.c index a8faf46adeb1..ba69846d444f 100644 --- a/drivers/video/fbdev/pm3fb.c +++ b/drivers/video/fbdev/pm3fb.c @@ -22,6 +22,7 @@ * */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -1315,6 +1316,10 @@ static int pm3fb_probe(struct pci_dev *dev, const struct pci_device_id *ent) int err; int retval = -ENXIO; + err = aperture_remove_conflicting_pci_devices(dev, "pm3fb"); + if (err) + return err; + err = pci_enable_device(dev); if (err) { printk(KERN_WARNING "pm3fb: Can't enable PCI dev: %d\n", err); diff --git a/drivers/video/fbdev/pvr2fb.c b/drivers/video/fbdev/pvr2fb.c index f4add36cb5f4..b73ad14efa20 100644 --- a/drivers/video/fbdev/pvr2fb.c +++ b/drivers/video/fbdev/pvr2fb.c @@ -45,6 +45,7 @@ #undef DEBUG +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -942,6 +943,10 @@ static int pvr2fb_pci_probe(struct pci_dev *pdev, { int ret; + ret = aperture_remove_conflicting_pci_devices(pdev, "pvrfb"); + if (ret) + return ret; + ret = pci_enable_device(pdev); if (ret) { printk(KERN_ERR "pvr2fb: PCI enable failed\n"); diff --git a/drivers/video/fbdev/riva/fbdev.c b/drivers/video/fbdev/riva/fbdev.c index 84d5e23ad7d3..0ea74e28f915 100644 --- a/drivers/video/fbdev/riva/fbdev.c +++ b/drivers/video/fbdev/riva/fbdev.c @@ -29,6 +29,7 @@ * doublescan modes are broken */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -474,7 +475,7 @@ static inline void reverse_order(u32 *l) * DESCRIPTiON: * Loads cursor image based on a monochrome source and mask bitmap. The * image bits determines the color of the pixel, 0 for background, 1 for - * foreground. Only the affected region (as determined by @w and @h + * foreground. Only the affected region (as determined by @w and @h * parameters) will be updated. * * CALLED FROM: @@ -494,7 +495,7 @@ static void rivafb_load_cursor_image(struct riva_par *par, u8 *data8, for (i = 0; i < h; i++) { b = *data++; reverse_order(&b); - + for (j = 0; j < w/2; j++) { tmp = 0; #if defined (__BIG_ENDIAN) @@ -562,7 +563,7 @@ static void riva_rclut(RIVA_HW_INST *chip, unsigned char regnum, unsigned char *red, unsigned char *green, unsigned char *blue) { - + VGA_WR08(chip->PDIO, 0x3c7, regnum); *red = VGA_RD08(chip->PDIO, 0x3c9); *green = VGA_RD08(chip->PDIO, 0x3c9); @@ -673,7 +674,7 @@ static int riva_load_video_mode(struct fb_info *info) int rc; struct riva_par *par = info->par; struct riva_regs newmode; - + NVTRACE_ENTER(); /* time to calculate */ rivafb_blank(FB_BLANK_NORMAL, info); @@ -717,7 +718,7 @@ static int riva_load_video_mode(struct fb_info *info) hBlankEnd = hTotal + 4; } - newmode.crtc[0x0] = Set8Bits (hTotal); + newmode.crtc[0x0] = Set8Bits (hTotal); newmode.crtc[0x1] = Set8Bits (hDisplay); newmode.crtc[0x2] = Set8Bits (hBlankStart); newmode.crtc[0x3] = SetBitField (hBlankEnd, 4: 0, 4:0) | SetBit (7); @@ -748,20 +749,20 @@ static int riva_load_video_mode(struct fb_info *info) | SetBitField(vStart,10:10,2:2) | SetBitField(vDisplay,10:10,1:1) | SetBitField(vTotal,10:10,0:0); - newmode.ext.horiz = SetBitField(hTotal,8:8,0:0) + newmode.ext.horiz = SetBitField(hTotal,8:8,0:0) | SetBitField(hDisplay,8:8,1:1) | SetBitField(hBlankStart,8:8,2:2) | SetBitField(hStart,8:8,3:3); newmode.ext.extra = SetBitField(vTotal,11:11,0:0) | SetBitField(vDisplay,11:11,2:2) | SetBitField(vStart,11:11,4:4) - | SetBitField(vBlankStart,11:11,6:6); + | SetBitField(vBlankStart,11:11,6:6); if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { int tmp = (hTotal >> 1) & ~1; newmode.ext.interlace = Set8Bits(tmp); newmode.ext.horiz |= SetBitField(tmp, 8:8,4:4); - } else + } else newmode.ext.interlace = 0xff; /* interlace off */ if (par->riva.Architecture >= NV_ARCH_10) @@ -774,7 +775,7 @@ static int riva_load_video_mode(struct fb_info *info) if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) newmode.misc_output &= ~0x80; else - newmode.misc_output |= 0x80; + newmode.misc_output |= 0x80; rc = CalcStateExt(&par->riva, &newmode.ext, par->pdev, bpp, width, hDisplaySize, height, dotClock); @@ -841,7 +842,7 @@ static void riva_update_var(struct fb_var_screeninfo *var, } /** - * rivafb_do_maximize - + * rivafb_do_maximize - * @info: pointer to fb_info object containing info for current riva board * @var: standard kernel fb changeable data * @nom: nom @@ -852,7 +853,7 @@ static void riva_update_var(struct fb_var_screeninfo *var, * * RETURNS: * -EINVAL on failure, 0 on success - * + * * * CALLED FROM: * rivafb_check_var() @@ -916,14 +917,14 @@ static int rivafb_do_maximize(struct fb_info *info, return -EINVAL; } } - + if (var->xres_virtual * nom / den >= 8192) { printk(KERN_WARNING PFX "virtual X resolution (%d) is too high, lowering to %d\n", var->xres_virtual, 8192 * den / nom - 16); var->xres_virtual = 8192 * den / nom - 16; } - + if (var->xres_virtual < var->xres) { printk(KERN_ERR PFX "virtual X resolution (%d) is smaller than real\n", var->xres_virtual); @@ -1010,7 +1011,7 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var) break; case 6: rc = 64; /* 64 entries (2^6), 16 bpp, RGB565 */ - break; + break; default: /* should not occur */ break; @@ -1042,7 +1043,7 @@ static int rivafb_open(struct fb_info *info, int user) /* vgaHWunlock() + riva unlock (0x7F) */ CRTCout(par, 0x11, 0xFF); par->riva.LockUnlock(&par->riva, 0); - + riva_save_state(par, &par->initial_state); } par->ref_count++; @@ -1082,7 +1083,7 @@ static int rivafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) struct riva_par *par = info->par; int nom, den; /* translating from pixels->bytes */ int mode_valid = 0; - + NVTRACE_ENTER(); if (!var->pixclock) return -EINVAL; @@ -1176,7 +1177,7 @@ static int rivafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) if (var->yoffset > var->yres_virtual - var->yres) var->yoffset = var->yres_virtual - var->yres - 1; - var->red.msb_right = + var->red.msb_right = var->green.msb_right = var->blue.msb_right = var->transp.offset = var->transp.length = var->transp.msb_right = 0; @@ -1198,7 +1199,7 @@ static int rivafb_set_par(struct fb_info *info) goto out; if(!(info->flags & FBINFO_HWACCEL_DISABLED)) riva_setup_accel(info); - + par->cursor_reset = 1; info->fix.line_length = (info->var.xres_virtual * (info->var.bits_per_pixel >> 3)); info->fix.visual = (info->var.bits_per_pixel == 8) ? @@ -1486,7 +1487,7 @@ static inline void convert_bgcolor_16(u32 *col) * CALLED FROM: * framebuffer hook */ -static void rivafb_imageblit(struct fb_info *info, +static void rivafb_imageblit(struct fb_info *info, const struct fb_image *image) { struct riva_par *par = info->par; @@ -1515,7 +1516,7 @@ static void rivafb_imageblit(struct fb_info *info, bgx = par->palette[image->bg_color]; } if (info->var.green.length == 6) - convert_bgcolor_16(&bgx); + convert_bgcolor_16(&bgx); break; } @@ -1612,7 +1613,7 @@ static int rivafb_cursor(struct fb_info *info, struct fb_cursor *cursor) u8 *dat = (u8 *) cursor->image.data; u8 *msk = (u8 *) cursor->mask; u8 *src; - + src = kmalloc_array(s_pitch, cursor->image.height, GFP_ATOMIC); if (src) { @@ -1683,7 +1684,7 @@ static const struct fb_ops riva_fb_ops = { .fb_fillrect = rivafb_fillrect, .fb_copyarea = rivafb_copyarea, .fb_imageblit = rivafb_imageblit, - .fb_cursor = rivafb_cursor, + .fb_cursor = rivafb_cursor, .fb_sync = rivafb_sync, }; @@ -1713,7 +1714,7 @@ static int riva_set_fbinfo(struct fb_info *info) info->pseudo_palette = par->pseudo_palette; cmap_len = riva_get_cmap_len(&info->var); - fb_alloc_cmap(&info->cmap, cmap_len, 0); + fb_alloc_cmap(&info->cmap, cmap_len, 0); info->pixmap.size = 8 * 1024; info->pixmap.buf_align = 4; @@ -1898,6 +1899,10 @@ static int rivafb_probe(struct pci_dev *pd, const struct pci_device_id *ent) NVTRACE_ENTER(); assert(pd != NULL); + ret = aperture_remove_conflicting_pci_devices(pd, "rivafb"); + if (ret) + return ret; + info = framebuffer_alloc(sizeof(struct riva_par), &pd->dev); if (!info) { ret = -ENOMEM; @@ -1929,7 +1934,7 @@ static int rivafb_probe(struct pci_dev *pd, const struct pci_device_id *ent) default_par->Chipset = (pd->vendor << 16) | pd->device; printk(KERN_INFO PFX "nVidia device/chipset %X\n",default_par->Chipset); - + if(default_par->riva.Architecture == 0) { printk(KERN_ERR PFX "unknown NV_ARCH\n"); ret=-ENODEV; @@ -1947,7 +1952,7 @@ static int rivafb_probe(struct pci_dev *pd, const struct pci_device_id *ent) if (flatpanel == 1) printk(KERN_INFO PFX "flatpanel support enabled\n"); default_par->forceCRTC = forceCRTC; - + rivafb_fix.mmio_len = pci_resource_len(pd, 0); rivafb_fix.smem_len = pci_resource_len(pd, 1); @@ -1959,7 +1964,7 @@ static int rivafb_probe(struct pci_dev *pd, const struct pci_device_id *ent) cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY); pci_write_config_word(pd, PCI_COMMAND, cmd); } - + rivafb_fix.mmio_start = pci_resource_start(pd, 0); rivafb_fix.smem_start = pci_resource_start(pd, 1); @@ -2058,7 +2063,7 @@ err_iounmap_screen_base: #endif iounmap(info->screen_base); err_iounmap_pramin: - if (default_par->riva.Architecture == NV_ARCH_03) + if (default_par->riva.Architecture == NV_ARCH_03) iounmap(default_par->riva.PRAMIN); err_iounmap_ctrl_base: iounmap(default_par->ctrl_base); @@ -2077,7 +2082,7 @@ static void rivafb_remove(struct pci_dev *pd) { struct fb_info *info = pci_get_drvdata(pd); struct riva_par *par = info->par; - + NVTRACE_ENTER(); #ifdef CONFIG_FB_RIVA_I2C @@ -2117,11 +2122,11 @@ static int rivafb_setup(char *options) while ((this_opt = strsep(&options, ",")) != NULL) { if (!strncmp(this_opt, "forceCRTC", 9)) { char *p; - + p = this_opt + 9; - if (!*p || !*(++p)) continue; + if (!*p || !*(++p)) continue; forceCRTC = *p - '0'; - if (forceCRTC < 0 || forceCRTC > 1) + if (forceCRTC < 0 || forceCRTC > 1) forceCRTC = -1; } else if (!strncmp(this_opt, "flatpanel", 9)) { flatpanel = 1; diff --git a/drivers/video/fbdev/s3fb.c b/drivers/video/fbdev/s3fb.c index 5069f6f67923..1882408b2d13 100644 --- a/drivers/video/fbdev/s3fb.c +++ b/drivers/video/fbdev/s3fb.c @@ -11,6 +11,7 @@ * which is based on the code of neofb. */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -1131,6 +1132,10 @@ static int s3_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) return -ENODEV; } + rc = aperture_remove_conflicting_pci_devices(dev, "s3fb"); + if (rc) + return rc; + /* Allocate and fill driver data structure */ info = framebuffer_alloc(sizeof(struct s3fb_info), &(dev->dev)); if (!info) diff --git a/drivers/video/fbdev/savage/savagefb_driver.c b/drivers/video/fbdev/savage/savagefb_driver.c index 8114c921ceb8..b7818b652698 100644 --- a/drivers/video/fbdev/savage/savagefb_driver.c +++ b/drivers/video/fbdev/savage/savagefb_driver.c @@ -41,6 +41,7 @@ * */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -2176,6 +2177,10 @@ static int savagefb_probe(struct pci_dev *dev, const struct pci_device_id *id) DBG("savagefb_probe"); + err = aperture_remove_conflicting_pci_devices(dev, "savagefb"); + if (err) + return err; + info = framebuffer_alloc(sizeof(struct savagefb_par), &dev->dev); if (!info) return -ENOMEM; diff --git a/drivers/video/fbdev/sis/sis_main.c b/drivers/video/fbdev/sis/sis_main.c index f28fd69d5eb7..7114c5c17c91 100644 --- a/drivers/video/fbdev/sis/sis_main.c +++ b/drivers/video/fbdev/sis/sis_main.c @@ -19,6 +19,7 @@ * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de> */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> @@ -5849,6 +5850,10 @@ static int sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if(sisfb_off) return -ENXIO; + ret = aperture_remove_conflicting_pci_devices(pdev, "sisfb"); + if (ret) + return ret; + sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev); if(!sis_fb_info) return -ENOMEM; diff --git a/drivers/video/fbdev/skeletonfb.c b/drivers/video/fbdev/skeletonfb.c index 8ab9a3fbd281..a10f1057293b 100644 --- a/drivers/video/fbdev/skeletonfb.c +++ b/drivers/video/fbdev/skeletonfb.c @@ -10,38 +10,39 @@ * The primary goal is to remove the console code from fbdev and place it * into fbcon.c. This reduces the code and makes writing a new fbdev driver * easy since the author doesn't need to worry about console internals. It - * also allows the ability to run fbdev without a console/tty system on top - * of it. + * also allows the ability to run fbdev without a console/tty system on top + * of it. * * First the roles of struct fb_info and struct display have changed. Struct * display will go away. The way the new framebuffer console code will - * work is that it will act to translate data about the tty/console in + * work is that it will act to translate data about the tty/console in * struct vc_data to data in a device independent way in struct fb_info. Then - * various functions in struct fb_ops will be called to store the device - * dependent state in the par field in struct fb_info and to change the + * various functions in struct fb_ops will be called to store the device + * dependent state in the par field in struct fb_info and to change the * hardware to that state. This allows a very clean separation of the fbdev * layer from the console layer. It also allows one to use fbdev on its own - * which is a bounus for embedded devices. The reason this approach works is + * which is a bounus for embedded devices. The reason this approach works is * for each framebuffer device when used as a tty/console device is allocated - * a set of virtual terminals to it. Only one virtual terminal can be active - * per framebuffer device. We already have all the data we need in struct + * a set of virtual terminals to it. Only one virtual terminal can be active + * per framebuffer device. We already have all the data we need in struct * vc_data so why store a bunch of colormaps and other fbdev specific data - * per virtual terminal. + * per virtual terminal. * * As you can see doing this makes the con parameter pretty much useless - * for struct fb_ops functions, as it should be. Also having struct - * fb_var_screeninfo and other data in fb_info pretty much eliminates the + * for struct fb_ops functions, as it should be. Also having struct + * fb_var_screeninfo and other data in fb_info pretty much eliminates the * need for get_fix and get_var. Once all drivers use the fix, var, and cmap * fbcon can be written around these fields. This will also eliminate the * need to regenerate struct fb_var_screeninfo, struct fb_fix_screeninfo * struct fb_cmap every time get_var, get_fix, get_cmap functions are called - * as many drivers do now. + * as many drivers do now. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -66,68 +67,68 @@ static char *mode_option; /* - * If your driver supports multiple boards, you should make the - * below data types arrays, or allocate them dynamically (using kmalloc()). - */ + * If your driver supports multiple boards, you should make the + * below data types arrays, or allocate them dynamically (using kmalloc()). + */ -/* +/* * This structure defines the hardware state of the graphics card. Normally * you place this in a header file in linux/include/video. This file usually * also includes register information. That allows other driver subsystems - * and userland applications the ability to use the same header file to - * avoid duplicate work and easy porting of software. + * and userland applications the ability to use the same header file to + * avoid duplicate work and easy porting of software. */ struct xxx_par; /* * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo * if we don't use modedb. If we do use modedb see xxxfb_init how to use it - * to get a fb_var_screeninfo. Otherwise define a default var as well. + * to get a fb_var_screeninfo. Otherwise define a default var as well. */ static const struct fb_fix_screeninfo xxxfb_fix = { - .id = "FB's name", + .id = "FB's name", .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_PSEUDOCOLOR, .xpanstep = 1, .ypanstep = 1, - .ywrapstep = 1, + .ywrapstep = 1, .accel = FB_ACCEL_NONE, }; /* - * Modern graphical hardware not only supports pipelines but some + * Modern graphical hardware not only supports pipelines but some * also support multiple monitors where each display can have - * its own unique data. In this case each display could be - * represented by a separate framebuffer device thus a separate + * its own unique data. In this case each display could be + * represented by a separate framebuffer device thus a separate * struct fb_info. Now the struct xxx_par represents the graphics - * hardware state thus only one exist per card. In this case the - * struct xxx_par for each graphics card would be shared between - * every struct fb_info that represents a framebuffer on that card. - * This allows when one display changes it video resolution (info->var) + * hardware state thus only one exist per card. In this case the + * struct xxx_par for each graphics card would be shared between + * every struct fb_info that represents a framebuffer on that card. + * This allows when one display changes it video resolution (info->var) * the other displays know instantly. Each display can always be * aware of the entire hardware state that affects it because they share * the same xxx_par struct. The other side of the coin is multiple * graphics cards that pass data around until it is finally displayed * on one monitor. Such examples are the voodoo 1 cards and high end * NUMA graphics servers. For this case we have a bunch of pars, each - * one that represents a graphics state, that belong to one struct + * one that represents a graphics state, that belong to one struct * fb_info. Their you would want to have *par point to a array of device - * states and have each struct fb_ops function deal with all those + * states and have each struct fb_ops function deal with all those * states. I hope this covers every possible hardware design. If not - * feel free to send your ideas at jsimmons@users.sf.net + * feel free to send your ideas at jsimmons@users.sf.net */ /* - * If your driver supports multiple boards or it supports multiple - * framebuffers, you should make these arrays, or allocate them + * If your driver supports multiple boards or it supports multiple + * framebuffers, you should make these arrays, or allocate them * dynamically using framebuffer_alloc() and free them with * framebuffer_release(). - */ + */ static struct fb_info info; - /* + /* * Each one represents the state of the hardware. Most hardware have - * just one hardware state. These here represent the default state(s). + * just one hardware state. These here represent the default state(s). */ static struct xxx_par __initdata current_par; @@ -136,12 +137,12 @@ static struct xxx_par __initdata current_par; * first accessed. * @info: frame buffer structure that represents a single frame buffer * @user: tell us if the userland (value=1) or the console is accessing - * the framebuffer. + * the framebuffer. * * This function is the first function called in the framebuffer api. - * Usually you don't need to provide this function. The case where it + * Usually you don't need to provide this function. The case where it * is used is to change from a text mode hardware state to a graphics - * mode state. + * mode state. * * Returns negative errno on error, or zero on success. */ @@ -151,13 +152,13 @@ static int xxxfb_open(struct fb_info *info, int user) } /** - * xxxfb_release - Optional function. Called when the framebuffer - * device is closed. + * xxxfb_release - Optional function. Called when the framebuffer + * device is closed. * @info: frame buffer structure that represents a single frame buffer * @user: tell us if the userland (value=1) or the console is accessing - * the framebuffer. - * - * Thus function is called when we close /dev/fb or the framebuffer + * the framebuffer. + * + * Thus function is called when we close /dev/fb or the framebuffer * console system is released. Usually you don't need this function. * The case where it is usually used is to go from a graphics state * to a text mode state. @@ -170,17 +171,17 @@ static int xxxfb_release(struct fb_info *info, int user) } /** - * xxxfb_check_var - Optional function. Validates a var passed in. + * xxxfb_check_var - Optional function. Validates a var passed in. * @var: frame buffer variable screen structure - * @info: frame buffer structure that represents a single frame buffer + * @info: frame buffer structure that represents a single frame buffer * * Checks to see if the hardware supports the state requested by - * var passed in. This function does not alter the hardware state!!! - * This means the data stored in struct fb_info and struct xxx_par do - * not change. This includes the var inside of struct fb_info. + * var passed in. This function does not alter the hardware state!!! + * This means the data stored in struct fb_info and struct xxx_par do + * not change. This includes the var inside of struct fb_info. * Do NOT change these. This function can be called on its own if we - * intent to only test a mode and not actually set it. The stuff in - * modedb.c is a example of this. If the var passed in is slightly + * intent to only test a mode and not actually set it. The stuff in + * modedb.c is a example of this. If the var passed in is slightly * off by what the hardware can support then we alter the var PASSED in * to what we can do. * @@ -208,7 +209,7 @@ static int xxxfb_release(struct fb_info *info, int user) static int xxxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { /* ... */ - return 0; + return 0; } /** @@ -217,9 +218,9 @@ static int xxxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) * * Using the fb_var_screeninfo in fb_info we set the resolution of the * this particular framebuffer. This function alters the par AND the - * fb_fix_screeninfo stored in fb_info. It doesn't not alter var in + * fb_fix_screeninfo stored in fb_info. It doesn't not alter var in * fb_info since we are using that data. This means we depend on the - * data in var inside fb_info to be supported by the hardware. + * data in var inside fb_info to be supported by the hardware. * * This function is also used to recover/restore the hardware to a * known working state. @@ -254,20 +255,20 @@ static int xxxfb_set_par(struct fb_info *info) { struct xxx_par *par = info->par; /* ... */ - return 0; + return 0; } /** * xxxfb_setcolreg - Optional function. Sets a color register. - * @regno: Which register in the CLUT we are programming - * @red: The red value which can be up to 16 bits wide - * @green: The green value which can be up to 16 bits wide + * @regno: Which register in the CLUT we are programming + * @red: The red value which can be up to 16 bits wide + * @green: The green value which can be up to 16 bits wide * @blue: The blue value which can be up to 16 bits wide. * @transp: If supported, the alpha value which can be up to 16 bits wide. * @info: frame buffer info structure - * + * * Set a single color register. The values supplied have a 16 bit - * magnitude which needs to be scaled in this function for the hardware. + * magnitude which needs to be scaled in this function for the hardware. * Things to take into consideration are how many color registers, if * any, are supported with the current color visual. With truecolor mode * no color palettes are supported. Here a pseudo palette is created @@ -275,8 +276,8 @@ static int xxxfb_set_par(struct fb_info *info) * pseudocolor mode we have a limited color palette. To deal with this * we can program what color is displayed for a particular pixel value. * DirectColor is similar in that we can program each color field. If - * we have a static colormap we don't need to implement this function. - * + * we have a static colormap we don't need to implement this function. + * * Returns negative errno on error, or zero on success. */ static int xxxfb_setcolreg(unsigned regno, unsigned red, unsigned green, @@ -440,7 +441,7 @@ static int xxxfb_pan_display(struct fb_var_screeninfo *var, /** * xxxfb_blank - NOT a required function. Blanks the display. - * @blank_mode: the blank mode we want. + * @blank_mode: the blank mode we want. * @info: frame buffer structure that represents a single frame buffer * * Blank the screen if blank_mode != FB_BLANK_UNBLANK, else unblank. @@ -469,22 +470,22 @@ static int xxxfb_blank(int blank_mode, struct fb_info *info) /* * We provide our own functions if we have hardware acceleration - * or non packed pixel format layouts. If we have no hardware + * or non packed pixel format layouts. If we have no hardware * acceleration, we can use a generic unaccelerated function. If using - * a pack pixel format just use the functions in cfb_*.c. Each file + * a pack pixel format just use the functions in cfb_*.c. Each file * has one of the three different accel functions we support. */ /** - * xxxfb_fillrect - REQUIRED function. Can use generic routines if + * xxxfb_fillrect - REQUIRED function. Can use generic routines if * non acclerated hardware and packed pixel based. - * Draws a rectangle on the screen. + * Draws a rectangle on the screen. * * @info: frame buffer structure that represents a single frame buffer - * @region: The structure representing the rectangular region we + * @region: The structure representing the rectangular region we * wish to draw to. * - * This drawing operation places/removes a retangle on the screen + * This drawing operation places/removes a retangle on the screen * depending on the rastering operation with the value of color which * is in the current color depth format. */ @@ -492,13 +493,13 @@ void xxxfb_fillrect(struct fb_info *p, const struct fb_fillrect *region) { /* Meaning of struct fb_fillrect * - * @dx: The x and y corrdinates of the upper left hand corner of the - * @dy: area we want to draw to. + * @dx: The x and y corrdinates of the upper left hand corner of the + * @dy: area we want to draw to. * @width: How wide the rectangle is we want to draw. * @height: How tall the rectangle is we want to draw. - * @color: The color to fill in the rectangle with. + * @color: The color to fill in the rectangle with. * @rop: The raster operation. We can draw the rectangle with a COPY - * of XOR which provides erasing effect. + * of XOR which provides erasing effect. */ } @@ -514,7 +515,7 @@ void xxxfb_fillrect(struct fb_info *p, const struct fb_fillrect *region) * This drawing operation copies a rectangular area from one area of the * screen to another area. */ -void xxxfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) +void xxxfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) { /* * @dx: The x and y coordinates of the upper left hand corner of the @@ -530,28 +531,28 @@ void xxxfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) /** * xxxfb_imageblit - REQUIRED function. Can use generic routines if * non acclerated hardware and packed pixel based. - * Copies a image from system memory to the screen. + * Copies a image from system memory to the screen. * * @info: frame buffer structure that represents a single frame buffer * @image: structure defining the image. * - * This drawing operation draws a image on the screen. It can be a + * This drawing operation draws a image on the screen. It can be a * mono image (needed for font handling) or a color image (needed for - * tux). + * tux). */ -void xxxfb_imageblit(struct fb_info *p, const struct fb_image *image) +void xxxfb_imageblit(struct fb_info *p, const struct fb_image *image) { /* * @dx: The x and y coordinates of the upper left hand corner of the * @dy: destination area to place the image on the screen. * @width: How wide the image is we want to copy. * @height: How tall the image is we want to copy. - * @fg_color: For mono bitmap images this is color data for + * @fg_color: For mono bitmap images this is color data for * @bg_color: the foreground and background of the image to * write directly to the frmaebuffer. * @depth: How many bits represent a single pixel for this image. * @data: The actual data used to construct the image on the display. - * @cmap: The colormap used for color images. + * @cmap: The colormap used for color images. */ /* @@ -578,13 +579,13 @@ void xxxfb_imageblit(struct fb_info *p, const struct fb_image *image) int xxxfb_cursor(struct fb_info *info, struct fb_cursor *cursor) { /* - * @set: Which fields we are altering in struct fb_cursor - * @enable: Disable or enable the cursor - * @rop: The bit operation we want to do. - * @mask: This is the cursor mask bitmap. + * @set: Which fields we are altering in struct fb_cursor + * @enable: Disable or enable the cursor + * @rop: The bit operation we want to do. + * @mask: This is the cursor mask bitmap. * @dest: A image of the area we are going to display the cursor. - * Used internally by the driver. - * @hot: The hot spot. + * Used internally by the driver. + * @hot: The hot spot. * @image: The actual data for the cursor image. * * NOTES ON FLAGS (cursor->set): @@ -612,11 +613,11 @@ int xxxfb_cursor(struct fb_info *info, struct fb_cursor *cursor) } /** - * xxxfb_sync - NOT a required function. Normally the accel engine + * xxxfb_sync - NOT a required function. Normally the accel engine * for a graphics card take a specific amount of time. * Often we have to wait for the accelerator to finish * its operation before we can write to the framebuffer - * so we can have consistent display output. + * so we can have consistent display output. * * @info: frame buffer structure that represents a single frame buffer * @@ -664,8 +665,15 @@ static int xxxfb_probe(struct pci_dev *dev, const struct pci_device_id *ent) struct fb_info *info; struct xxx_par *par; struct device *device = &dev->dev; /* or &pdev->dev */ - int cmap_len, retval; - + int cmap_len, retval; + + /* + * Remove firmware-based drivers that create resource conflicts. + */ + retval = aperture_remove_conflicting_pci_devices(pdev, "xxxfb"); + if (retval) + return retval; + /* * Dynamically allocate info and par */ @@ -677,11 +685,11 @@ static int xxxfb_probe(struct pci_dev *dev, const struct pci_device_id *ent) par = info->par; - /* + /* * Here we set the screen_base to the virtual memory address * for the framebuffer. Usually we obtain the resource address * from the bus layer and then translate it to virtual memory - * space via ioremap. Consult ioport.h. + * space via ioremap. Consult ioport.h. */ info->screen_base = framebuffer_virtual_memory; info->fbops = &xxxfb_ops; @@ -765,24 +773,24 @@ static int xxxfb_probe(struct pci_dev *dev, const struct pci_device_id *ent) /* * This should give a reasonable default video mode. The following is - * done when we can set a video mode. + * done when we can set a video mode. */ if (!mode_option) - mode_option = "640x480@60"; + mode_option = "640x480@60"; retval = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); - + if (!retval || retval == 4) - return -EINVAL; + return -EINVAL; /* This has to be done! */ if (fb_alloc_cmap(&info->cmap, cmap_len, 0)) return -ENOMEM; - - /* - * The following is done in the case of having hardware with a static - * mode. If we are setting the mode ourselves we don't call this. - */ + + /* + * The following is done in the case of having hardware with a static + * mode. If we are setting the mode ourselves we don't call this. + */ info->var = xxxfb_var; /* diff --git a/drivers/video/fbdev/sm712fb.c b/drivers/video/fbdev/sm712fb.c index 092a1caa1208..3baf33635e65 100644 --- a/drivers/video/fbdev/sm712fb.c +++ b/drivers/video/fbdev/sm712fb.c @@ -18,6 +18,7 @@ * Framebuffer driver for Silicon Motion SM710, SM712, SM721 and SM722 chips */ +#include <linux/aperture.h> #include <linux/io.h> #include <linux/fb.h> #include <linux/pci.h> @@ -1502,6 +1503,10 @@ static int smtcfb_pci_probe(struct pci_dev *pdev, dev_info(&pdev->dev, "Silicon Motion display driver.\n"); + err = aperture_remove_conflicting_pci_devices(pdev, "smtcfb"); + if (err) + return err; + err = pci_enable_device(pdev); /* enable SMTC chip */ if (err) return err; diff --git a/drivers/video/fbdev/sstfb.c b/drivers/video/fbdev/sstfb.c index 27d4b0ace2d6..73ca2782ebfc 100644 --- a/drivers/video/fbdev/sstfb.c +++ b/drivers/video/fbdev/sstfb.c @@ -80,6 +80,7 @@ * Includes */ +#include <linux/aperture.h> #include <linux/string.h> #include <linux/kernel.h> #include <linux/module.h> @@ -364,7 +365,7 @@ static int sstfb_check_var(struct fb_var_screeninfo *var, return -EINVAL; } var->pixclock = KHZ2PICOS(freq); - + if (var->vmode & FB_VMODE_INTERLACED) vBackPorch += (vBackPorch % 2); if (var->vmode & FB_VMODE_DOUBLE) { @@ -382,7 +383,7 @@ static int sstfb_check_var(struct fb_var_screeninfo *var, printk(KERN_ERR "sstfb: Unsupported bpp %d\n", var->bits_per_pixel); return -EINVAL; } - + /* validity tests */ if (var->xres <= 1 || yDim <= 0 || var->hsync_len <= 1 || hSyncOff <= 1 || var->left_margin <= 2 || vSyncOn <= 0 || @@ -392,7 +393,7 @@ static int sstfb_check_var(struct fb_var_screeninfo *var, if (IS_VOODOO2(par)) { /* Voodoo 2 limits */ - tiles_in_X = (var->xres + 63 ) / 64 * 2; + tiles_in_X = (var->xres + 63 ) / 64 * 2; if (var->xres > POW2(11) || yDim >= POW2(11)) { printk(KERN_ERR "sstfb: Unsupported resolution %dx%d\n", @@ -631,7 +632,7 @@ static int sstfb_set_par(struct fb_info *info) lfbmode |= ( LFB_WORD_SWIZZLE_WR | LFB_BYTE_SWIZZLE_WR | LFB_WORD_SWIZZLE_RD | LFB_BYTE_SWIZZLE_RD ); #endif - + if (clipping) { sst_write(LFBMODE, lfbmode | EN_PXL_PIPELINE); /* @@ -684,7 +685,7 @@ static int sstfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | (green << info->var.green.offset) | (blue << info->var.blue.offset) | (transp << info->var.transp.offset); - + par->palette[regno] = col; return 0; @@ -773,7 +774,7 @@ static void sstfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) { struct sstfb_par *par = info->par; u32 stride = info->fix.line_length; - + if (!IS_VOODOO2(par)) return; @@ -795,17 +796,17 @@ static void sstfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) * FillRect 2D command (solidfill or invert (via ROP_XOR)) - Voodoo2 only */ #if 0 -static void sstfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +static void sstfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct sstfb_par *par = info->par; u32 stride = info->fix.line_length; if (!IS_VOODOO2(par)) return; - + sst_write(BLTCLIPX, info->var.xres); sst_write(BLTCLIPY, info->var.yres); - + sst_write(BLTDSTBASEADDR, 0); sst_write(BLTCOLOR, rect->color); sst_write(BLTROP, rect->rop == ROP_COPY ? BLTROP_COPY : BLTROP_XOR); @@ -820,8 +821,8 @@ static void sstfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) -/* - * get lfb size +/* + * get lfb size */ static int sst_get_memsize(struct fb_info *info, __u32 *memsize) { @@ -859,8 +860,8 @@ static int sst_get_memsize(struct fb_info *info, __u32 *memsize) } -/* - * DAC detection routines +/* + * DAC detection routines */ /* fbi should be idle, and fifo emty and mem disabled */ @@ -963,7 +964,7 @@ static int sst_detect_ics(struct fb_info *info) * see detect_dac */ -static int sst_set_pll_att_ti(struct fb_info *info, +static int sst_set_pll_att_ti(struct fb_info *info, const struct pll_timing *t, const int clock) { struct sstfb_par *par = info->par; @@ -1326,6 +1327,10 @@ static int sstfb_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct sst_spec *spec; int err; + err = aperture_remove_conflicting_pci_devices(pdev, "sstfb"); + if (err) + return err; + /* Enable device in PCI config. */ if ((err=pci_enable_device(pdev))) { printk(KERN_ERR "cannot enable device\n"); @@ -1338,10 +1343,10 @@ static int sstfb_probe(struct pci_dev *pdev, const struct pci_device_id *id) return -ENOMEM; pci_set_drvdata(pdev, info); - + par = info->par; fix = &info->fix; - + par->type = id->driver_data; spec = &voodoo_spec[par->type]; f_ddprintk("found device : %s\n", spec->name); @@ -1407,7 +1412,7 @@ static int sstfb_probe(struct pci_dev *pdev, const struct pci_device_id *id) * fact dithered to 16bit). */ fix->line_length = 2048; /* default value, for 24 or 32bit: 4096 */ - + fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 16); if (sstfb_check_var(&info->var, info)) { @@ -1419,7 +1424,7 @@ static int sstfb_probe(struct pci_dev *pdev, const struct pci_device_id *id) printk(KERN_ERR "sstfb: can't set default video mode.\n"); goto fail; } - + if (fb_alloc_cmap(&info->cmap, 256, 0)) { printk(KERN_ERR "sstfb: can't alloc cmap memory.\n"); goto fail; @@ -1465,7 +1470,7 @@ static void sstfb_remove(struct pci_dev *pdev) info = pci_get_drvdata(pdev); par = info->par; - + device_remove_file(info->dev, &device_attrs[0]); sst_shutdown(info); iounmap(info->screen_base); diff --git a/drivers/video/fbdev/sunxvr2500.c b/drivers/video/fbdev/sunxvr2500.c index 1d3bacd9d5ac..81d59613ea1f 100644 --- a/drivers/video/fbdev/sunxvr2500.c +++ b/drivers/video/fbdev/sunxvr2500.c @@ -5,6 +5,7 @@ * Copyright (C) 2007 David S. Miller (davem@davemloft.net) */ +#include <linux/aperture.h> #include <linux/kernel.h> #include <linux/fb.h> #include <linux/pci.h> @@ -123,6 +124,10 @@ static int s3d_pci_register(struct pci_dev *pdev, struct s3d_info *sp; int err; + err = aperture_remove_conflicting_pci_devices(pdev, "s3dfb"); + if (err) + return err; + err = pci_enable_device(pdev); if (err < 0) { printk(KERN_ERR "s3d: Cannot enable PCI device %s\n", diff --git a/drivers/video/fbdev/sunxvr500.c b/drivers/video/fbdev/sunxvr500.c index 9daf17b11106..3a51b2a1480c 100644 --- a/drivers/video/fbdev/sunxvr500.c +++ b/drivers/video/fbdev/sunxvr500.c @@ -5,6 +5,7 @@ * Copyright (C) 2007 David S. Miller (davem@davemloft.net) */ +#include <linux/aperture.h> #include <linux/kernel.h> #include <linux/fb.h> #include <linux/pci.h> @@ -249,6 +250,10 @@ static int e3d_pci_register(struct pci_dev *pdev, unsigned int line_length; int err; + err = aperture_remove_conflicting_pci_devices(pdev, "e3dfb"); + if (err) + return err; + of_node = pci_device_to_OF_node(pdev); if (!of_node) { printk(KERN_ERR "e3d: Cannot find OF node of %s\n", diff --git a/drivers/video/fbdev/tdfxfb.c b/drivers/video/fbdev/tdfxfb.c index 67e37a62b07c..059e0174e139 100644 --- a/drivers/video/fbdev/tdfxfb.c +++ b/drivers/video/fbdev/tdfxfb.c @@ -64,6 +64,7 @@ * */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -1376,6 +1377,10 @@ static int tdfxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct fb_monspecs *specs; bool found; + err = aperture_remove_conflicting_pci_devices(pdev, "tdfxfb"); + if (err) + return err; + err = pci_enable_device(pdev); if (err) { printk(KERN_ERR "tdfxfb: Can't enable pdev: %d\n", err); diff --git a/drivers/video/fbdev/tgafb.c b/drivers/video/fbdev/tgafb.c index ae0cf5540636..4600138e3bef 100644 --- a/drivers/video/fbdev/tgafb.c +++ b/drivers/video/fbdev/tgafb.c @@ -12,6 +12,7 @@ * more details. */ +#include <linux/aperture.h> #include <linux/bitrev.h> #include <linux/compiler.h> #include <linux/delay.h> @@ -106,6 +107,12 @@ static struct pci_driver tgafb_pci_driver = { static int tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) { + int ret; + + ret = aperture_remove_conflicting_pci_devices(pdev, "tgafb"); + if (ret) + return ret; + return tgafb_register(&pdev->dev); } @@ -729,7 +736,7 @@ tgafb_mono_imageblit(struct fb_info *info, const struct fb_image *image) /* Handle another common case in which accel_putcs generates a large bitmap, which happens to be aligned. - Allow the tail to be misaligned. This case is + Allow the tail to be misaligned. This case is interesting because we've not got to hold partial bytes across the words being written. */ @@ -908,9 +915,9 @@ tgafb_imageblit(struct fb_info *info, const struct fb_image *image) } /** - * tgafb_fillrect - REQUIRED function. Can use generic routines if + * tgafb_fillrect - REQUIRED function. Can use generic routines if * non acclerated hardware and packed pixel based. - * Draws a rectangle on the screen. + * Draws a rectangle on the screen. * * @info: frame buffer structure that represents a single frame buffer * @rect: structure defining the rectagle and operation. @@ -1044,7 +1051,7 @@ tgafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) /* Handle the special case of copying entire lines, e.g. during scrolling. We can avoid a lot of needless computation in this case. In the 8bpp - case we need to use the COPY64 registers instead of mask writes into + case we need to use the COPY64 registers instead of mask writes into the frame buffer to achieve maximum performance. */ static inline void @@ -1251,7 +1258,7 @@ copyarea_8bpp(struct fb_info *info, u32 dx, u32 dy, u32 sx, u32 sy, } static void -tgafb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +tgafb_copyarea(struct fb_info *info, const struct fb_copyarea *area) { unsigned long dx, dy, width, height, sx, sy, vxres, vyres; unsigned long line_length, bpp; diff --git a/drivers/video/fbdev/tridentfb.c b/drivers/video/fbdev/tridentfb.c index 319131bd72cf..6813df793c49 100644 --- a/drivers/video/fbdev/tridentfb.c +++ b/drivers/video/fbdev/tridentfb.c @@ -16,6 +16,7 @@ * timing value tweaking so it looks good on every monitor in every mode */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/fb.h> #include <linux/init.h> @@ -1470,6 +1471,10 @@ static int trident_pci_probe(struct pci_dev *dev, int chip_id; bool found = false; + err = aperture_remove_conflicting_pci_devices(dev, "tridentfb"); + if (err) + return err; + err = pci_enable_device(dev); if (err) return err; diff --git a/drivers/video/fbdev/vermilion/vermilion.c b/drivers/video/fbdev/vermilion/vermilion.c index ff61605b8764..82b36dbb5b1a 100644 --- a/drivers/video/fbdev/vermilion/vermilion.c +++ b/drivers/video/fbdev/vermilion/vermilion.c @@ -14,6 +14,7 @@ * Alan Hourihane <alanh-at-tungstengraphics-dot-com> */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -442,7 +443,11 @@ static int vml_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) struct vml_info *vinfo; struct fb_info *info; struct vml_par *par; - int err = 0; + int err; + + err = aperture_remove_conflicting_pci_devices(dev, "vmlfb"); + if (err) + return err; par = kzalloc(sizeof(*par), GFP_KERNEL); if (par == NULL) diff --git a/drivers/video/fbdev/vga16fb.c b/drivers/video/fbdev/vga16fb.c index d21f68f3ee44..35cf51ae3292 100644 --- a/drivers/video/fbdev/vga16fb.c +++ b/drivers/video/fbdev/vga16fb.c @@ -1,13 +1,13 @@ /* * linux/drivers/video/vga16.c -- VGA 16-color framebuffer driver - * + * * Copyright 1999 Ben Pfaff <pfaffben@debian.org> and Petr Vandrovec <VANDROVE@vc.cvut.cz> * Based on VGA info at http://www.goodnet.com/~tinara/FreeVGA/home.htm * Based on VESA framebuffer (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de> * * This file is subject to the terms and conditions of the GNU General * Public License. See the file COPYING in the main directory of this - * archive for more details. + * archive for more details. */ #include <linux/module.h> @@ -25,9 +25,6 @@ #include <asm/io.h> #include <video/vga.h> -#define VGA_FB_PHYS 0xA0000 -#define VGA_FB_PHYS_LEN 65536 - #define MODE_SKIP4 1 #define MODE_8BPP 2 #define MODE_CFB 4 @@ -70,7 +67,7 @@ static struct fb_var_screeninfo vga16fb_defined = { .yres = 480, .xres_virtual = 640, .yres_virtual = 480, - .bits_per_pixel = 4, + .bits_per_pixel = 4, .activate = FB_ACTIVATE_TEST, .height = -1, .width = -1, @@ -87,8 +84,8 @@ static struct fb_var_screeninfo vga16fb_defined = { /* name should not depend on EGA/VGA */ static const struct fb_fix_screeninfo vga16fb_fix = { .id = "VGA16 VGA", - .smem_start = VGA_FB_PHYS, - .smem_len = VGA_FB_PHYS_LEN, + .smem_start = VGA_FB_PHYS_BASE, + .smem_len = VGA_FB_PHYS_SIZE, .type = FB_TYPE_VGA_PLANES, .type_aux = FB_AUX_VGA_PLANES_VGA4, .visual = FB_VISUAL_PSEUDOCOLOR, @@ -120,7 +117,7 @@ static inline void rmw(volatile char __iomem *p) static inline int setmode(int mode) { int oldmode; - + oldmode = vga_io_rgfx(VGA_GFX_MODE); vga_io_w(VGA_GFX_D, mode); return oldmode; @@ -139,19 +136,19 @@ static inline void setmask(int mask) vga_io_w(VGA_GFX_D, mask); } -/* Set the Data Rotate Register and return its old value. +/* Set the Data Rotate Register and return its old value. Bits 0-2 are rotate count, bits 3-4 are logical operation (0=NOP, 1=AND, 2=OR, 3=XOR). */ static inline int setop(int op) { int oldop; - + oldop = vga_io_rgfx(VGA_GFX_DATA_ROTATE); vga_io_w(VGA_GFX_D, op); return oldop; } -/* Set the Enable Set/Reset Register and return its old value. +/* Set the Enable Set/Reset Register and return its old value. The code here always uses value 0xf for this register. */ static inline int setsr(int sr) { @@ -185,25 +182,25 @@ static inline void setindex(int index) } /* Check if the video mode is supported by the driver */ -static inline int check_mode_supported(void) +static inline int check_mode_supported(const struct screen_info *si) { /* non-x86 architectures treat orig_video_isVGA as a boolean flag */ #if defined(CONFIG_X86) /* only EGA and VGA in 16 color graphic mode are supported */ - if (screen_info.orig_video_isVGA != VIDEO_TYPE_EGAC && - screen_info.orig_video_isVGA != VIDEO_TYPE_VGAC) + if (si->orig_video_isVGA != VIDEO_TYPE_EGAC && + si->orig_video_isVGA != VIDEO_TYPE_VGAC) return -ENODEV; - if (screen_info.orig_video_mode != 0x0D && /* 320x200/4 (EGA) */ - screen_info.orig_video_mode != 0x0E && /* 640x200/4 (EGA) */ - screen_info.orig_video_mode != 0x10 && /* 640x350/4 (EGA) */ - screen_info.orig_video_mode != 0x12) /* 640x480/4 (VGA) */ + if (si->orig_video_mode != 0x0D && /* 320x200/4 (EGA) */ + si->orig_video_mode != 0x0E && /* 640x200/4 (EGA) */ + si->orig_video_mode != 0x10 && /* 640x350/4 (EGA) */ + si->orig_video_mode != 0x12) /* 640x480/4 (VGA) */ return -ENODEV; #endif return 0; } -static void vga16fb_pan_var(struct fb_info *info, +static void vga16fb_pan_var(struct fb_info *info, struct fb_var_screeninfo *var) { struct vga16fb_par *par = info->par; @@ -296,7 +293,7 @@ static void vga16fb_clock_chip(struct vga16fb_par *par, par->clkdiv = best->seq_clock_mode; *pixclock = (best->pixclock * div) / mul; } - + #define FAIL(X) return -EINVAL static int vga16fb_open(struct fb_info *info, int user) @@ -511,7 +508,7 @@ static int vga16fb_check_var(struct fb_var_screeninfo *var, par->misc &= ~0x40; if (var->sync & FB_SYNC_VERT_HIGH_ACT) par->misc &= ~0x80; - + par->mode = mode; if (mode & MODE_8BPP) @@ -520,8 +517,8 @@ static int vga16fb_check_var(struct fb_var_screeninfo *var, else /* pixel clock == vga clock */ vga16fb_clock_chip(par, &var->pixclock, info, 1, 1); - - var->red.offset = var->green.offset = var->blue.offset = + + var->red.offset = var->green.offset = var->blue.offset = var->transp.offset = 0; var->red.length = var->green.length = var->blue.length = (par->isVGA) ? 6 : 2; @@ -588,10 +585,10 @@ static int vga16fb_set_par(struct fb_info *info) else atc[VGA_ATC_PEL] = info->var.xoffset & 7; atc[VGA_ATC_COLOR_PAGE] = 0x00; - + if (par->mode & MODE_TEXT) { - fh = 16; // FIXME !!! Fudge font height. - par->crtc[VGA_CRTC_MAX_SCAN] = (par->crtc[VGA_CRTC_MAX_SCAN] + fh = 16; // FIXME !!! Fudge font height. + par->crtc[VGA_CRTC_MAX_SCAN] = (par->crtc[VGA_CRTC_MAX_SCAN] & ~0x1F) | (fh - 1); } @@ -602,10 +599,10 @@ static int vga16fb_set_par(struct fb_info *info) vga_io_w(EGA_GFX_E0, 0x00); vga_io_w(EGA_GFX_E1, 0x01); } - + /* update misc output register */ vga_io_w(VGA_MIS_W, par->misc); - + /* synchronous reset on */ vga_io_wseq(0x00, 0x01); @@ -617,7 +614,7 @@ static int vga16fb_set_par(struct fb_info *info) for (i = 2; i < VGA_SEQ_C; i++) { vga_io_wseq(i, seq[i]); } - + /* synchronous reset off */ vga_io_wseq(0x00, 0x03); @@ -628,12 +625,12 @@ static int vga16fb_set_par(struct fb_info *info) for (i = 0; i < VGA_CRTC_REGS; i++) { vga_io_wcrt(i, par->crtc[i]); } - + /* write graphics controller registers */ for (i = 0; i < VGA_GFX_C; i++) { vga_io_wgfx(i, gdc[i]); } - + /* write attribute controller registers */ for (i = 0; i < VGA_ATT_C; i++) { vga_io_r(VGA_IS1_RC); /* reset flip-flop */ @@ -656,7 +653,7 @@ static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned b { static const unsigned char map[] = { 000, 001, 010, 011 }; int val; - + if (regno >= 16) return; val = map[red>>14] | ((map[green>>14]) << 1) | ((map[blue>>14]) << 2); @@ -687,17 +684,17 @@ static int vga16fb_setcolreg(unsigned regno, unsigned red, unsigned green, * (according to the entries in the `var' structure). Return * != 0 for invalid regno. */ - + if (regno >= 256) return 1; gray = info->var.grayscale; - + if (gray) { /* gray = 0.30*R + 0.59*G + 0.11*B */ red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; } - if (par->isVGA) + if (par->isVGA) vga16_setpalette(regno,red,green,blue); else ega16_setpalette(regno,red,green,blue); @@ -705,7 +702,7 @@ static int vga16fb_setcolreg(unsigned regno, unsigned red, unsigned green, } static int vga16fb_pan_display(struct fb_var_screeninfo *var, - struct fb_info *info) + struct fb_info *info) { vga16fb_pan_var(info, var); return 0; @@ -720,7 +717,7 @@ static void vga_vesa_blank(struct vga16fb_par *par, int mode) { unsigned char SeqCtrlIndex = vga_io_r(VGA_SEQ_I); unsigned char CrtCtrlIndex = vga_io_r(VGA_CRT_IC); - + /* save original values of VGA controller registers */ if(!par->vesa_blanked) { par->vga_state.CrtMiscIO = vga_io_r(VGA_MIS_R); @@ -776,7 +773,7 @@ static void vga_vesa_unblank(struct vga16fb_par *par) { unsigned char SeqCtrlIndex = vga_io_r(VGA_SEQ_I); unsigned char CrtCtrlIndex = vga_io_r(VGA_CRT_IC); - + /* restore original values of VGA controller registers */ vga_io_w(VGA_MIS_W, par->vga_state.CrtMiscIO); @@ -962,7 +959,7 @@ static void vga16fb_fillrect(struct fb_info *info, const struct fb_fillrect *rec } break; } - } else + } else vga_8planes_fillrect(info, rect); break; case FB_TYPE_PACKED_PIXELS: @@ -1029,7 +1026,7 @@ static void vga_8planes_copyarea(struct fb_info *info, const struct fb_copyarea static void vga16fb_copyarea(struct fb_info *info, const struct fb_copyarea *area) { - u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; + u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; int x, x2, y2, old_dx, old_dy, vxres, vyres; int height, width, line_ofs; char __iomem *dst = NULL; @@ -1094,9 +1091,9 @@ static void vga16fb_copyarea(struct fb_info *info, const struct fb_copyarea *are dst += line_ofs; } } else { - dst = info->screen_base + (dx/8) + width + + dst = info->screen_base + (dx/8) + width + (dy + height - 1) * info->fix.line_length; - src = info->screen_base + (sx/8) + width + + src = info->screen_base + (sx/8) + width + (sy + height - 1) * info->fix.line_length; while (height--) { for (x = 0; x < width; x++) { @@ -1109,7 +1106,7 @@ static void vga16fb_copyarea(struct fb_info *info, const struct fb_copyarea *are dst -= line_ofs; } } - } else + } else vga_8planes_copyarea(info, area); break; case FB_TYPE_PACKED_PIXELS: @@ -1182,7 +1179,7 @@ static void vga_imageblit_expand(struct fb_info *info, const struct fb_image *im setsr(0xf); setcolor(image->fg_color); selectmask(); - + setmask(0xff); writeb(image->bg_color, where); rmb(); @@ -1191,7 +1188,7 @@ static void vga_imageblit_expand(struct fb_info *info, const struct fb_image *im wmb(); for (y = 0; y < image->height; y++) { dst = where; - for (x = image->width/8; x--;) + for (x = image->width/8; x--;) writeb(*cdat++, dst++); where += info->fix.line_length; } @@ -1202,7 +1199,7 @@ static void vga_imageblit_expand(struct fb_info *info, const struct fb_image *im setsr(0xf); setcolor(image->bg_color); selectmask(); - + setmask(0xff); for (y = 0; y < image->height; y++) { dst = where; @@ -1218,7 +1215,7 @@ static void vga_imageblit_expand(struct fb_info *info, const struct fb_image *im where += info->fix.line_length; } } - } else + } else vga_8planes_imageblit(info, image); break; case FB_TYPE_PACKED_PIXELS: @@ -1231,7 +1228,7 @@ static void vga_imageblit_expand(struct fb_info *info, const struct fb_image *im static void vga_imageblit_color(struct fb_info *info, const struct fb_image *image) { /* - * Draw logo + * Draw logo */ struct vga16fb_par *par = info->par; char __iomem *where = @@ -1248,7 +1245,7 @@ static void vga_imageblit_color(struct fb_info *info, const struct fb_image *ima setsr(0xf); setop(0); setmode(0); - + for (y = 0; y < image->height; y++) { for (x = 0; x < image->width; x++) { dst = where + x/8; @@ -1272,7 +1269,7 @@ static void vga_imageblit_color(struct fb_info *info, const struct fb_image *ima break; } } - + static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image) { if (image->depth == 1) @@ -1304,28 +1301,22 @@ static const struct fb_ops vga16fb_ops = { .fb_imageblit = vga16fb_imageblit, }; -#ifndef MODULE -static int __init vga16fb_setup(char *options) -{ - char *this_opt; - - if (!options || !*options) - return 0; - - while ((this_opt = strsep(&options, ",")) != NULL) { - if (!*this_opt) continue; - } - return 0; -} -#endif - static int vga16fb_probe(struct platform_device *dev) { + struct screen_info *si; struct fb_info *info; struct vga16fb_par *par; int i; int ret = 0; + si = dev_get_platdata(&dev->dev); + if (!si) + return -ENODEV; + + ret = check_mode_supported(si); + if (ret) + return ret; + printk(KERN_DEBUG "vga16fb: initializing\n"); info = framebuffer_alloc(sizeof(struct vga16fb_par), &dev->dev); @@ -1339,8 +1330,8 @@ static int vga16fb_probe(struct platform_device *dev) goto err_ioremap; } - /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */ - info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS, 0); + /* XXX share VGA_FB_PHYS_BASE and I/O region with vgacon and others */ + info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS_BASE, 0); if (!info->screen_base) { printk(KERN_ERR "vga16fb: unable to map device\n"); @@ -1352,19 +1343,19 @@ static int vga16fb_probe(struct platform_device *dev) par = info->par; #if defined(CONFIG_X86) - par->isVGA = screen_info.orig_video_isVGA == VIDEO_TYPE_VGAC; + par->isVGA = si->orig_video_isVGA == VIDEO_TYPE_VGAC; #else /* non-x86 architectures treat orig_video_isVGA as a boolean flag */ - par->isVGA = screen_info.orig_video_isVGA; + par->isVGA = si->orig_video_isVGA; #endif par->palette_blanked = 0; par->vesa_blanked = 0; i = par->isVGA? 6 : 2; - + vga16fb_defined.red.length = i; vga16fb_defined.green.length = i; - vga16fb_defined.blue.length = i; + vga16fb_defined.blue.length = i; /* name should not depend on EGA/VGA */ info->fbops = &vga16fb_ops; @@ -1391,8 +1382,8 @@ static int vga16fb_probe(struct platform_device *dev) vga16fb_update_fix(info); - info->apertures->ranges[0].base = VGA_FB_PHYS; - info->apertures->ranges[0].size = VGA_FB_PHYS_LEN; + info->apertures->ranges[0].base = VGA_FB_PHYS_BASE; + info->apertures->ranges[0].size = VGA_FB_PHYS_SIZE; if (register_framebuffer(info) < 0) { printk(KERN_ERR "vga16fb: unable to register framebuffer\n"); @@ -1425,58 +1416,22 @@ static int vga16fb_remove(struct platform_device *dev) return 0; } +static const struct platform_device_id vga16fb_driver_id_table[] = { + {"ega-framebuffer", 0}, + {"vga-framebuffer", 0}, + { } +}; + static struct platform_driver vga16fb_driver = { .probe = vga16fb_probe, .remove = vga16fb_remove, .driver = { .name = "vga16fb", }, + .id_table = vga16fb_driver_id_table, }; -static struct platform_device *vga16fb_device; - -static int __init vga16fb_init(void) -{ - int ret; -#ifndef MODULE - char *option = NULL; - - if (fb_get_options("vga16fb", &option)) - return -ENODEV; - - vga16fb_setup(option); -#endif - - ret = check_mode_supported(); - if (ret) - return ret; - - ret = platform_driver_register(&vga16fb_driver); - - if (!ret) { - vga16fb_device = platform_device_alloc("vga16fb", 0); - - if (vga16fb_device) - ret = platform_device_add(vga16fb_device); - else - ret = -ENOMEM; - - if (ret) { - platform_device_put(vga16fb_device); - platform_driver_unregister(&vga16fb_driver); - } - } - - return ret; -} - -static void __exit vga16fb_exit(void) -{ - platform_device_unregister(vga16fb_device); - platform_driver_unregister(&vga16fb_driver); -} +module_platform_driver(vga16fb_driver); MODULE_DESCRIPTION("Legacy VGA framebuffer device driver"); MODULE_LICENSE("GPL"); -module_init(vga16fb_init); -module_exit(vga16fb_exit); diff --git a/drivers/video/fbdev/via/via-core.c b/drivers/video/fbdev/via/via-core.c index 89d75079b730..2ee8fcae08df 100644 --- a/drivers/video/fbdev/via/via-core.c +++ b/drivers/video/fbdev/via/via-core.c @@ -8,6 +8,7 @@ /* * Core code for the Via multifunction framebuffer device. */ +#include <linux/aperture.h> #include <linux/via-core.h> #include <linux/via_i2c.h> #include <linux/via-gpio.h> @@ -617,6 +618,10 @@ static int via_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int ret; + ret = aperture_remove_conflicting_pci_devices(pdev, "viafb"); + if (ret) + return ret; + ret = pci_enable_device(pdev); if (ret) return ret; diff --git a/drivers/video/fbdev/vt8623fb.c b/drivers/video/fbdev/vt8623fb.c index 4274c6efb249..49b9f148d3a1 100644 --- a/drivers/video/fbdev/vt8623fb.c +++ b/drivers/video/fbdev/vt8623fb.c @@ -12,6 +12,7 @@ * (http://davesdomain.org.uk/viafb/) */ +#include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -672,6 +673,10 @@ static int vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) return -ENODEV; } + rc = aperture_remove_conflicting_pci_devices(dev, "vt8623fb"); + if (rc) + return rc; + /* Allocate and fill driver data structure */ info = framebuffer_alloc(sizeof(struct vt8623fb_info), &(dev->dev)); if (!info) |