Merge drm/drm-next into drm-intel-next
Backmerge to sync the DP MST atomic changes to drm-intel-next. Signed-off-by: Jani Nikula <jani.nikula@intel.com>
This commit is contained in:
commit
6f3562b3bc
@ -24,6 +24,15 @@ properties:
|
||||
maxItems: 1
|
||||
description: virtual channel number of a DSI peripheral
|
||||
|
||||
clock-names:
|
||||
const: refclk
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
description: |
|
||||
Optional external clock connected to REF_CLK input.
|
||||
The clock rate must be in 10..154 MHz range.
|
||||
|
||||
enable-gpios:
|
||||
description: Bridge EN pin, chip is reset when EN is low.
|
||||
|
||||
|
@ -14,6 +14,19 @@ properties:
|
||||
compatible:
|
||||
const: chrontel,ch7033
|
||||
|
||||
chrontel,byteswap:
|
||||
$ref: /schemas/types.yaml#/definitions/uint8
|
||||
enum:
|
||||
- 0 # BYTE_SWAP_RGB
|
||||
- 1 # BYTE_SWAP_RBG
|
||||
- 2 # BYTE_SWAP_GRB
|
||||
- 3 # BYTE_SWAP_GBR
|
||||
- 4 # BYTE_SWAP_BRG
|
||||
- 5 # BYTE_SWAP_BGR
|
||||
description: |
|
||||
Set the byteswap value of the bridge. This is optional and if not
|
||||
set value of BYTE_SWAP_BGR is used.
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
description: I2C address of the device
|
||||
|
@ -17,6 +17,8 @@ properties:
|
||||
enum:
|
||||
- ingenic,jz4740-lcd
|
||||
- ingenic,jz4725b-lcd
|
||||
- ingenic,jz4760-lcd
|
||||
- ingenic,jz4760b-lcd
|
||||
- ingenic,jz4770-lcd
|
||||
- ingenic,jz4780-lcd
|
||||
|
||||
|
@ -0,0 +1,116 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/mediatek/mediatek,dp.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MediaTek Display Port Controller
|
||||
|
||||
maintainers:
|
||||
- Chun-Kuang Hu <chunkuang.hu@kernel.org>
|
||||
- Jitao shi <jitao.shi@mediatek.com>
|
||||
|
||||
description: |
|
||||
MediaTek DP and eDP are different hardwares and there are some features
|
||||
which are not supported for eDP. For example, audio is not supported for
|
||||
eDP. Therefore, we need to use two different compatibles to describe them.
|
||||
In addition, We just need to enable the power domain of DP, so the clock
|
||||
of DP is generated by itself and we are not using other PLL to generate
|
||||
clocks.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt8195-dp-tx
|
||||
- mediatek,mt8195-edp-tx
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
nvmem-cells:
|
||||
maxItems: 1
|
||||
description: efuse data for display port calibration
|
||||
|
||||
nvmem-cell-names:
|
||||
const: dp_calibration_data
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
properties:
|
||||
port@0:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: Input endpoint of the controller, usually dp_intf
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
description: Output endpoint of the controller
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
properties:
|
||||
data-lanes:
|
||||
description: |
|
||||
number of lanes supported by the hardware.
|
||||
The possible values:
|
||||
0 - For 1 lane enabled in IP.
|
||||
0 1 - For 2 lanes enabled in IP.
|
||||
0 1 2 3 - For 4 lanes enabled in IP.
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
required:
|
||||
- data-lanes
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
max-linkrate-mhz:
|
||||
enum: [ 1620, 2700, 5400, 8100 ]
|
||||
description: maximum link rate supported by the hardware.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- ports
|
||||
- max-linkrate-mhz
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/power/mt8195-power.h>
|
||||
dptx@1c600000 {
|
||||
compatible = "mediatek,mt8195-dp-tx";
|
||||
reg = <0x1c600000 0x8000>;
|
||||
power-domains = <&spm MT8195_POWER_DOMAIN_DP_TX>;
|
||||
interrupts = <GIC_SPI 458 IRQ_TYPE_LEVEL_HIGH 0>;
|
||||
max-linkrate-mhz = <8100>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
dptx_in: endpoint {
|
||||
remote-endpoint = <&dp_intf0_out>;
|
||||
};
|
||||
};
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
dptx_out: endpoint {
|
||||
data-lanes = <0 1 2 3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -280,6 +280,8 @@ properties:
|
||||
- samsung,atna33xc20
|
||||
# Samsung 12.2" (2560x1600 pixels) TFT LCD panel
|
||||
- samsung,lsn122dl01-c01
|
||||
# Samsung Electronics 10.1" WXGA (1280x800) TFT LCD panel
|
||||
- samsung,ltl101al01
|
||||
# Samsung Electronics 10.1" WSVGA TFT LCD panel
|
||||
- samsung,ltn101nt05
|
||||
# Samsung Electronics 14" WXGA (1366x768) TFT LCD panel
|
||||
|
@ -17,6 +17,9 @@ description: |
|
||||
Techstar TS8550B is 480x854, 2-lane MIPI DSI LCD panel which has
|
||||
inbuilt ST7701 chip.
|
||||
|
||||
Densitron DMT028VGHMCMI-1A is 480x640, 2-lane MIPI DSI LCD panel
|
||||
which has built-in ST7701 chip.
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
@ -24,6 +27,7 @@ properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- densitron,dmt028vghmcmi-1a
|
||||
- techstar,ts8550b
|
||||
- const: sitronix,st7701
|
||||
|
||||
|
@ -122,13 +122,13 @@ format Helper Functions Reference
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_format_helper.c
|
||||
:export:
|
||||
|
||||
Framebuffer CMA Helper Functions Reference
|
||||
Framebuffer DMA Helper Functions Reference
|
||||
==========================================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_fb_cma_helper.c
|
||||
:doc: framebuffer cma helper functions
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_fb_dma_helper.c
|
||||
:doc: framebuffer dma helper functions
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_fb_cma_helper.c
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_fb_dma_helper.c
|
||||
:export:
|
||||
|
||||
Framebuffer GEM Helper Reference
|
||||
|
@ -300,12 +300,12 @@ Drivers that want to map the GEM object upfront instead of handling page
|
||||
faults can implement their own mmap file operation handler.
|
||||
|
||||
For platforms without MMU the GEM core provides a helper method
|
||||
drm_gem_cma_get_unmapped_area(). The mmap() routines will call this to get a
|
||||
drm_gem_dma_get_unmapped_area(). The mmap() routines will call this to get a
|
||||
proposed address for the mapping.
|
||||
|
||||
To use drm_gem_cma_get_unmapped_area(), drivers must fill the struct
|
||||
To use drm_gem_dma_get_unmapped_area(), drivers must fill the struct
|
||||
:c:type:`struct file_operations <file_operations>` get_unmapped_area field with
|
||||
a pointer on drm_gem_cma_get_unmapped_area().
|
||||
a pointer on drm_gem_dma_get_unmapped_area().
|
||||
|
||||
More detailed information about get_unmapped_area can be found in
|
||||
Documentation/admin-guide/mm/nommu-mmap.rst
|
||||
@ -355,16 +355,16 @@ GEM Function Reference
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_gem.c
|
||||
:export:
|
||||
|
||||
GEM CMA Helper Functions Reference
|
||||
GEM DMA Helper Functions Reference
|
||||
----------------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_gem_cma_helper.c
|
||||
:doc: cma helpers
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_gem_dma_helper.c
|
||||
:doc: dma helpers
|
||||
|
||||
.. kernel-doc:: include/drm/drm_gem_cma_helper.h
|
||||
.. kernel-doc:: include/drm/drm_gem_dma_helper.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_gem_cma_helper.c
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_gem_dma_helper.c
|
||||
:export:
|
||||
|
||||
GEM SHMEM Helper Function Reference
|
||||
|
@ -322,18 +322,6 @@ Contact: Daniel Vetter, Noralf Tronnes
|
||||
|
||||
Level: Advanced
|
||||
|
||||
idr_init_base()
|
||||
---------------
|
||||
|
||||
DRM core&drivers uses a lot of idr (integer lookup directories) for mapping
|
||||
userspace IDs to internal objects, and in most places ID=0 means NULL and hence
|
||||
is never used. Switching to idr_init_base() for these would make the idr more
|
||||
efficient.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Level: Starter
|
||||
|
||||
struct drm_gem_object_funcs
|
||||
---------------------------
|
||||
|
||||
@ -343,19 +331,6 @@ converted, except for struct drm_driver.gem_prime_mmap.
|
||||
|
||||
Level: Intermediate
|
||||
|
||||
Rename CMA helpers to DMA helpers
|
||||
---------------------------------
|
||||
|
||||
CMA (standing for contiguous memory allocator) is really a bit an accident of
|
||||
what these were used for first, a much better name would be DMA helpers. In the
|
||||
text these should even be called coherent DMA memory helpers (so maybe CDM, but
|
||||
no one knows what that means) since underneath they just use dma_alloc_coherent.
|
||||
|
||||
Contact: Laurent Pinchart, Daniel Vetter
|
||||
|
||||
Level: Intermediate (mostly because it is a huge tasks without good partial
|
||||
milestones, not technically itself that challenging)
|
||||
|
||||
connector register/unregister fixes
|
||||
-----------------------------------
|
||||
|
||||
@ -617,17 +592,6 @@ Contact: Javier Martinez Canillas <javierm@redhat.com>
|
||||
|
||||
Level: Intermediate
|
||||
|
||||
Convert Kernel Selftests (kselftest) to KUnit tests when appropriate
|
||||
--------------------------------------------------------------------
|
||||
|
||||
Many of the `Kselftest <https://www.kernel.org/doc/html/latest/dev-tools/kselftest.html>`_
|
||||
tests in DRM could be converted to Kunit tests instead, since that framework
|
||||
is more suitable for unit testing.
|
||||
|
||||
Contact: Javier Martinez Canillas <javierm@redhat.com>
|
||||
|
||||
Level: Starter
|
||||
|
||||
Enable trinity for DRM
|
||||
----------------------
|
||||
|
||||
|
@ -118,15 +118,10 @@ Add Plane Features
|
||||
|
||||
There's lots of plane features we could add support for:
|
||||
|
||||
- Clearing primary plane: clear primary plane before plane composition (at the
|
||||
start) for correctness of pixel blend ops. It also guarantees alpha channel
|
||||
is cleared in the target buffer for stable crc. [Good to get started]
|
||||
|
||||
- ARGB format on primary plane: blend the primary plane into background with
|
||||
translucent alpha.
|
||||
|
||||
- Support when the primary plane isn't exactly matching the output size: blend
|
||||
the primary plane into the black background.
|
||||
- Add background color KMS property[Good to get started].
|
||||
|
||||
- Full alpha blending on all planes.
|
||||
|
||||
|
@ -6419,6 +6419,11 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.yaml
|
||||
F: drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
|
||||
|
||||
DRM DRIVER FOR GENERIC EDP PANELS
|
||||
R: Douglas Anderson <dianders@chromium.org>
|
||||
F: Documentation/devicetree/bindings/display/panel/panel-edp.yaml
|
||||
F: drivers/gpu/drm/panel/panel-edp.c
|
||||
|
||||
DRM DRIVER FOR GENERIC USB DISPLAY
|
||||
M: Noralf Trønnes <noralf@tronnes.org>
|
||||
S: Maintained
|
||||
|
@ -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);
|
||||
|
@ -124,17 +124,20 @@ static int begin_cpu_udmabuf(struct dma_buf *buf,
|
||||
{
|
||||
struct udmabuf *ubuf = buf->priv;
|
||||
struct device *dev = ubuf->device->this_device;
|
||||
int ret = 0;
|
||||
|
||||
if (!ubuf->sg) {
|
||||
ubuf->sg = get_sg_table(dev, buf, direction);
|
||||
if (IS_ERR(ubuf->sg))
|
||||
return PTR_ERR(ubuf->sg);
|
||||
if (IS_ERR(ubuf->sg)) {
|
||||
ret = PTR_ERR(ubuf->sg);
|
||||
ubuf->sg = NULL;
|
||||
}
|
||||
} else {
|
||||
dma_sync_sg_for_cpu(dev, ubuf->sg->sgl, ubuf->sg->nents,
|
||||
direction);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int end_cpu_udmabuf(struct dma_buf *buf,
|
||||
|
@ -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";
|
||||
|
||||
|
@ -31,6 +31,7 @@ menuconfig DRM
|
||||
config DRM_MIPI_DBI
|
||||
tristate
|
||||
depends on DRM
|
||||
select DRM_KMS_HELPER
|
||||
|
||||
config DRM_MIPI_DSI
|
||||
bool
|
||||
@ -50,10 +51,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 +61,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 +201,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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -204,6 +204,42 @@ void amdgpu_gtt_mgr_recover(struct amdgpu_gtt_mgr *mgr)
|
||||
amdgpu_gart_invalidate_tlb(adev);
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_gtt_mgr_intersects - test for intersection
|
||||
*
|
||||
* @man: Our manager object
|
||||
* @res: The resource to test
|
||||
* @place: The place for the new allocation
|
||||
* @size: The size of the new allocation
|
||||
*
|
||||
* Simplified intersection test, only interesting if we need GART or not.
|
||||
*/
|
||||
static bool amdgpu_gtt_mgr_intersects(struct ttm_resource_manager *man,
|
||||
struct ttm_resource *res,
|
||||
const struct ttm_place *place,
|
||||
size_t size)
|
||||
{
|
||||
return !place->lpfn || amdgpu_gtt_mgr_has_gart_addr(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_gtt_mgr_compatible - test for compatibility
|
||||
*
|
||||
* @man: Our manager object
|
||||
* @res: The resource to test
|
||||
* @place: The place for the new allocation
|
||||
* @size: The size of the new allocation
|
||||
*
|
||||
* Simplified compatibility test.
|
||||
*/
|
||||
static bool amdgpu_gtt_mgr_compatible(struct ttm_resource_manager *man,
|
||||
struct ttm_resource *res,
|
||||
const struct ttm_place *place,
|
||||
size_t size)
|
||||
{
|
||||
return !place->lpfn || amdgpu_gtt_mgr_has_gart_addr(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_gtt_mgr_debug - dump VRAM table
|
||||
*
|
||||
@ -225,6 +261,8 @@ static void amdgpu_gtt_mgr_debug(struct ttm_resource_manager *man,
|
||||
static const struct ttm_resource_manager_func amdgpu_gtt_mgr_func = {
|
||||
.alloc = amdgpu_gtt_mgr_new,
|
||||
.free = amdgpu_gtt_mgr_del,
|
||||
.intersects = amdgpu_gtt_mgr_intersects,
|
||||
.compatible = amdgpu_gtt_mgr_compatible,
|
||||
.debug = amdgpu_gtt_mgr_debug
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
@ -1329,11 +1330,12 @@ uint64_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
|
||||
static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo,
|
||||
const struct ttm_place *place)
|
||||
{
|
||||
unsigned long num_pages = bo->resource->num_pages;
|
||||
struct dma_resv_iter resv_cursor;
|
||||
struct amdgpu_res_cursor cursor;
|
||||
struct dma_fence *f;
|
||||
|
||||
if (!amdgpu_bo_is_amdgpu_bo(bo))
|
||||
return ttm_bo_eviction_valuable(bo, place);
|
||||
|
||||
/* Swapout? */
|
||||
if (bo->resource->mem_type == TTM_PL_SYSTEM)
|
||||
return true;
|
||||
@ -1352,39 +1354,19 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo,
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (bo->resource->mem_type) {
|
||||
case AMDGPU_PL_PREEMPT:
|
||||
/* Preemptible BOs don't own system resources managed by the
|
||||
* driver (pages, VRAM, GART space). They point to resources
|
||||
* owned by someone else (e.g. pageable memory in user mode
|
||||
* or a DMABuf). They are used in a preemptible context so we
|
||||
* can guarantee no deadlocks and good QoS in case of MMU
|
||||
* notifiers or DMABuf move notifiers from the resource owner.
|
||||
*/
|
||||
return false;
|
||||
case TTM_PL_TT:
|
||||
if (amdgpu_bo_is_amdgpu_bo(bo) &&
|
||||
amdgpu_bo_encrypted(ttm_to_amdgpu_bo(bo)))
|
||||
return false;
|
||||
return true;
|
||||
|
||||
case TTM_PL_VRAM:
|
||||
/* Check each drm MM node individually */
|
||||
amdgpu_res_first(bo->resource, 0, (u64)num_pages << PAGE_SHIFT,
|
||||
&cursor);
|
||||
while (cursor.remaining) {
|
||||
if (place->fpfn < PFN_DOWN(cursor.start + cursor.size)
|
||||
&& !(place->lpfn &&
|
||||
place->lpfn <= PFN_DOWN(cursor.start)))
|
||||
return true;
|
||||
|
||||
amdgpu_res_next(&cursor, cursor.size);
|
||||
}
|
||||
/* Preemptible BOs don't own system resources managed by the
|
||||
* driver (pages, VRAM, GART space). They point to resources
|
||||
* owned by someone else (e.g. pageable memory in user mode
|
||||
* or a DMABuf). They are used in a preemptible context so we
|
||||
* can guarantee no deadlocks and good QoS in case of MMU
|
||||
* notifiers or DMABuf move notifiers from the resource owner.
|
||||
*/
|
||||
if (bo->resource->mem_type == AMDGPU_PL_PREEMPT)
|
||||
return false;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (bo->resource->mem_type == TTM_PL_TT &&
|
||||
amdgpu_bo_encrypted(ttm_to_amdgpu_bo(bo)))
|
||||
return false;
|
||||
|
||||
return ttm_bo_eviction_valuable(bo, place);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -720,6 +720,72 @@ uint64_t amdgpu_vram_mgr_vis_usage(struct amdgpu_vram_mgr *mgr)
|
||||
return atomic64_read(&mgr->vis_usage);
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_vram_mgr_intersects - test each drm buddy block for intersection
|
||||
*
|
||||
* @man: TTM memory type manager
|
||||
* @res: The resource to test
|
||||
* @place: The place to test against
|
||||
* @size: Size of the new allocation
|
||||
*
|
||||
* Test each drm buddy block for intersection for eviction decision.
|
||||
*/
|
||||
static bool amdgpu_vram_mgr_intersects(struct ttm_resource_manager *man,
|
||||
struct ttm_resource *res,
|
||||
const struct ttm_place *place,
|
||||
size_t size)
|
||||
{
|
||||
struct amdgpu_vram_mgr_resource *mgr = to_amdgpu_vram_mgr_resource(res);
|
||||
struct drm_buddy_block *block;
|
||||
|
||||
/* Check each drm buddy block individually */
|
||||
list_for_each_entry(block, &mgr->blocks, link) {
|
||||
unsigned long fpfn =
|
||||
amdgpu_vram_mgr_block_start(block) >> PAGE_SHIFT;
|
||||
unsigned long lpfn = fpfn +
|
||||
(amdgpu_vram_mgr_block_size(block) >> PAGE_SHIFT);
|
||||
|
||||
if (place->fpfn < lpfn &&
|
||||
(place->lpfn && place->lpfn > fpfn))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_vram_mgr_compatible - test each drm buddy block for compatibility
|
||||
*
|
||||
* @man: TTM memory type manager
|
||||
* @res: The resource to test
|
||||
* @place: The place to test against
|
||||
* @size: Size of the new allocation
|
||||
*
|
||||
* Test each drm buddy block for placement compatibility.
|
||||
*/
|
||||
static bool amdgpu_vram_mgr_compatible(struct ttm_resource_manager *man,
|
||||
struct ttm_resource *res,
|
||||
const struct ttm_place *place,
|
||||
size_t size)
|
||||
{
|
||||
struct amdgpu_vram_mgr_resource *mgr = to_amdgpu_vram_mgr_resource(res);
|
||||
struct drm_buddy_block *block;
|
||||
|
||||
/* Check each drm buddy block individually */
|
||||
list_for_each_entry(block, &mgr->blocks, link) {
|
||||
unsigned long fpfn =
|
||||
amdgpu_vram_mgr_block_start(block) >> PAGE_SHIFT;
|
||||
unsigned long lpfn = fpfn +
|
||||
(amdgpu_vram_mgr_block_size(block) >> PAGE_SHIFT);
|
||||
|
||||
if (fpfn < place->fpfn ||
|
||||
(place->lpfn && lpfn > place->lpfn))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_vram_mgr_debug - dump VRAM table
|
||||
*
|
||||
@ -753,6 +819,8 @@ static void amdgpu_vram_mgr_debug(struct ttm_resource_manager *man,
|
||||
static const struct ttm_resource_manager_func amdgpu_vram_mgr_func = {
|
||||
.alloc = amdgpu_vram_mgr_new,
|
||||
.free = amdgpu_vram_mgr_del,
|
||||
.intersects = amdgpu_vram_mgr_intersects,
|
||||
.compatible = amdgpu_vram_mgr_compatible,
|
||||
.debug = amdgpu_vram_mgr_debug
|
||||
};
|
||||
|
||||
|
@ -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"
|
||||
|
||||
@ -2807,20 +2808,18 @@ static const struct drm_mode_config_funcs amdgpu_dm_mode_funcs = {
|
||||
};
|
||||
|
||||
static struct drm_mode_config_helper_funcs amdgpu_dm_mode_config_helperfuncs = {
|
||||
.atomic_commit_tail = amdgpu_dm_atomic_commit_tail
|
||||
.atomic_commit_tail = amdgpu_dm_atomic_commit_tail,
|
||||
.atomic_commit_setup = drm_dp_mst_atomic_setup_commit,
|
||||
};
|
||||
|
||||
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 +2841,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 +2852,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(
|
||||
@ -6321,10 +6296,17 @@ amdgpu_dm_connector_atomic_check(struct drm_connector *conn,
|
||||
drm_atomic_get_old_connector_state(state, conn);
|
||||
struct drm_crtc *crtc = new_con_state->crtc;
|
||||
struct drm_crtc_state *new_crtc_state;
|
||||
struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(conn);
|
||||
int ret;
|
||||
|
||||
trace_amdgpu_dm_connector_atomic_check(new_con_state);
|
||||
|
||||
if (conn->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
|
||||
ret = drm_dp_mst_root_conn_atomic_check(new_con_state, &aconn->mst_mgr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!crtc)
|
||||
return 0;
|
||||
|
||||
@ -6408,6 +6390,7 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
|
||||
struct drm_dp_mst_topology_mgr *mst_mgr;
|
||||
struct drm_dp_mst_port *mst_port;
|
||||
struct drm_dp_mst_topology_state *mst_state;
|
||||
enum dc_color_depth color_depth;
|
||||
int clock, bpp = 0;
|
||||
bool is_y420 = false;
|
||||
@ -6421,6 +6404,13 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
|
||||
if (!crtc_state->connectors_changed && !crtc_state->mode_changed)
|
||||
return 0;
|
||||
|
||||
mst_state = drm_atomic_get_mst_topology_state(state, mst_mgr);
|
||||
if (IS_ERR(mst_state))
|
||||
return PTR_ERR(mst_state);
|
||||
|
||||
if (!mst_state->pbn_div)
|
||||
mst_state->pbn_div = dm_mst_get_pbn_divider(aconnector->mst_port->dc_link);
|
||||
|
||||
if (!state->duplicated) {
|
||||
int max_bpc = conn_state->max_requested_bpc;
|
||||
is_y420 = drm_mode_is_420_also(&connector->display_info, adjusted_mode) &&
|
||||
@ -6432,11 +6422,10 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
|
||||
clock = adjusted_mode->clock;
|
||||
dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp, false);
|
||||
}
|
||||
dm_new_connector_state->vcpi_slots = drm_dp_atomic_find_vcpi_slots(state,
|
||||
mst_mgr,
|
||||
mst_port,
|
||||
dm_new_connector_state->pbn,
|
||||
dm_mst_get_pbn_divider(aconnector->dc_link));
|
||||
|
||||
dm_new_connector_state->vcpi_slots =
|
||||
drm_dp_atomic_find_time_slots(state, mst_mgr, mst_port,
|
||||
dm_new_connector_state->pbn);
|
||||
if (dm_new_connector_state->vcpi_slots < 0) {
|
||||
DRM_DEBUG_ATOMIC("failed finding vcpi slots: %d\n", (int)dm_new_connector_state->vcpi_slots);
|
||||
return dm_new_connector_state->vcpi_slots;
|
||||
@ -6506,18 +6495,12 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
|
||||
dm_conn_state->pbn = pbn;
|
||||
dm_conn_state->vcpi_slots = slot_num;
|
||||
|
||||
drm_dp_mst_atomic_enable_dsc(state,
|
||||
aconnector->port,
|
||||
dm_conn_state->pbn,
|
||||
0,
|
||||
drm_dp_mst_atomic_enable_dsc(state, aconnector->port, dm_conn_state->pbn,
|
||||
false);
|
||||
continue;
|
||||
}
|
||||
|
||||
vcpi = drm_dp_mst_atomic_enable_dsc(state,
|
||||
aconnector->port,
|
||||
pbn, pbn_div,
|
||||
true);
|
||||
vcpi = drm_dp_mst_atomic_enable_dsc(state, aconnector->port, pbn, true);
|
||||
if (vcpi < 0)
|
||||
return vcpi;
|
||||
|
||||
@ -7992,6 +7975,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
DRM_ERROR("Waiting for fences timed out!");
|
||||
|
||||
drm_atomic_helper_update_legacy_modeset_state(dev, state);
|
||||
drm_dp_mst_atomic_wait_for_dependencies(state);
|
||||
|
||||
dm_state = dm_atomic_get_new_state(state);
|
||||
if (dm_state && dm_state->context) {
|
||||
@ -8390,7 +8374,6 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
dc_release_state(dc_state_temp);
|
||||
}
|
||||
|
||||
|
||||
static int dm_force_atomic_commit(struct drm_connector *connector)
|
||||
{
|
||||
int ret = 0;
|
||||
@ -9361,8 +9344,6 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
|
||||
struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
|
||||
#if defined(CONFIG_DRM_AMD_DC_DCN)
|
||||
struct dsc_mst_fairness_vars vars[MAX_PIPES];
|
||||
struct drm_dp_mst_topology_state *mst_state;
|
||||
struct drm_dp_mst_topology_mgr *mgr;
|
||||
#endif
|
||||
|
||||
trace_amdgpu_dm_atomic_check_begin(state);
|
||||
@ -9601,33 +9582,6 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
|
||||
lock_and_validation_needed = true;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DRM_AMD_DC_DCN)
|
||||
/* set the slot info for each mst_state based on the link encoding format */
|
||||
for_each_new_mst_mgr_in_state(state, mgr, mst_state, i) {
|
||||
struct amdgpu_dm_connector *aconnector;
|
||||
struct drm_connector *connector;
|
||||
struct drm_connector_list_iter iter;
|
||||
u8 link_coding_cap;
|
||||
|
||||
if (!mgr->mst_state )
|
||||
continue;
|
||||
|
||||
drm_connector_list_iter_begin(dev, &iter);
|
||||
drm_for_each_connector_iter(connector, &iter) {
|
||||
int id = connector->index;
|
||||
|
||||
if (id == mst_state->mgr->conn_base_id) {
|
||||
aconnector = to_amdgpu_dm_connector(connector);
|
||||
link_coding_cap = dc_link_dp_mst_decide_link_encoding_format(aconnector->dc_link);
|
||||
drm_dp_mst_update_slots(mst_state, link_coding_cap);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
drm_connector_list_iter_end(&iter);
|
||||
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* Streams and planes are reset when there are changes that affect
|
||||
* bandwidth. Anything that affects bandwidth needs to go through
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/amdgpu_drm.h>
|
||||
#include <drm/drm_edid.h>
|
||||
@ -153,41 +154,28 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
|
||||
return result;
|
||||
}
|
||||
|
||||
static void get_payload_table(
|
||||
struct amdgpu_dm_connector *aconnector,
|
||||
struct dp_mst_stream_allocation_table *proposed_table)
|
||||
static void
|
||||
fill_dc_mst_payload_table_from_drm(struct drm_dp_mst_topology_state *mst_state,
|
||||
struct amdgpu_dm_connector *aconnector,
|
||||
struct dc_dp_mst_stream_allocation_table *table)
|
||||
{
|
||||
int i;
|
||||
struct drm_dp_mst_topology_mgr *mst_mgr =
|
||||
&aconnector->mst_port->mst_mgr;
|
||||
struct dc_dp_mst_stream_allocation_table new_table = { 0 };
|
||||
struct dc_dp_mst_stream_allocation *sa;
|
||||
struct drm_dp_mst_atomic_payload *payload;
|
||||
|
||||
mutex_lock(&mst_mgr->payload_lock);
|
||||
/* Fill payload info*/
|
||||
list_for_each_entry(payload, &mst_state->payloads, next) {
|
||||
if (payload->delete)
|
||||
continue;
|
||||
|
||||
proposed_table->stream_count = 0;
|
||||
|
||||
/* number of active streams */
|
||||
for (i = 0; i < mst_mgr->max_payloads; i++) {
|
||||
if (mst_mgr->payloads[i].num_slots == 0)
|
||||
break; /* end of vcp_id table */
|
||||
|
||||
ASSERT(mst_mgr->payloads[i].payload_state !=
|
||||
DP_PAYLOAD_DELETE_LOCAL);
|
||||
|
||||
if (mst_mgr->payloads[i].payload_state == DP_PAYLOAD_LOCAL ||
|
||||
mst_mgr->payloads[i].payload_state ==
|
||||
DP_PAYLOAD_REMOTE) {
|
||||
|
||||
struct dp_mst_stream_allocation *sa =
|
||||
&proposed_table->stream_allocations[
|
||||
proposed_table->stream_count];
|
||||
|
||||
sa->slot_count = mst_mgr->payloads[i].num_slots;
|
||||
sa->vcp_id = mst_mgr->proposed_vcpis[i]->vcpi;
|
||||
proposed_table->stream_count++;
|
||||
}
|
||||
sa = &new_table.stream_allocations[new_table.stream_count];
|
||||
sa->slot_count = payload->time_slots;
|
||||
sa->vcp_id = payload->vcpi;
|
||||
new_table.stream_count++;
|
||||
}
|
||||
|
||||
mutex_unlock(&mst_mgr->payload_lock);
|
||||
/* Overwrite the old table */
|
||||
*table = new_table;
|
||||
}
|
||||
|
||||
void dm_helpers_dp_update_branch_info(
|
||||
@ -201,15 +189,13 @@ void dm_helpers_dp_update_branch_info(
|
||||
bool dm_helpers_dp_mst_write_payload_allocation_table(
|
||||
struct dc_context *ctx,
|
||||
const struct dc_stream_state *stream,
|
||||
struct dp_mst_stream_allocation_table *proposed_table,
|
||||
struct dc_dp_mst_stream_allocation_table *proposed_table,
|
||||
bool enable)
|
||||
{
|
||||
struct amdgpu_dm_connector *aconnector;
|
||||
struct dm_connector_state *dm_conn_state;
|
||||
struct drm_dp_mst_topology_state *mst_state;
|
||||
struct drm_dp_mst_atomic_payload *payload;
|
||||
struct drm_dp_mst_topology_mgr *mst_mgr;
|
||||
struct drm_dp_mst_port *mst_port;
|
||||
bool ret;
|
||||
u8 link_coding_cap = DP_8b_10b_ENCODING;
|
||||
|
||||
aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
|
||||
/* Accessing the connector state is required for vcpi_slots allocation
|
||||
@ -220,40 +206,21 @@ bool dm_helpers_dp_mst_write_payload_allocation_table(
|
||||
if (!aconnector || !aconnector->mst_port)
|
||||
return false;
|
||||
|
||||
dm_conn_state = to_dm_connector_state(aconnector->base.state);
|
||||
|
||||
mst_mgr = &aconnector->mst_port->mst_mgr;
|
||||
|
||||
if (!mst_mgr->mst_state)
|
||||
return false;
|
||||
|
||||
mst_port = aconnector->port;
|
||||
|
||||
#if defined(CONFIG_DRM_AMD_DC_DCN)
|
||||
link_coding_cap = dc_link_dp_mst_decide_link_encoding_format(aconnector->dc_link);
|
||||
#endif
|
||||
|
||||
if (enable) {
|
||||
|
||||
ret = drm_dp_mst_allocate_vcpi(mst_mgr, mst_port,
|
||||
dm_conn_state->pbn,
|
||||
dm_conn_state->vcpi_slots);
|
||||
if (!ret)
|
||||
return false;
|
||||
|
||||
} else {
|
||||
drm_dp_mst_reset_vcpi_slots(mst_mgr, mst_port);
|
||||
}
|
||||
mst_state = to_drm_dp_mst_topology_state(mst_mgr->base.state);
|
||||
|
||||
/* It's OK for this to fail */
|
||||
drm_dp_update_payload_part1(mst_mgr, (link_coding_cap == DP_CAP_ANSI_128B132B) ? 0:1);
|
||||
payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->port);
|
||||
if (enable)
|
||||
drm_dp_add_payload_part1(mst_mgr, mst_state, payload);
|
||||
else
|
||||
drm_dp_remove_payload(mst_mgr, mst_state, payload);
|
||||
|
||||
/* mst_mgr->->payloads are VC payload notify MST branch using DPCD or
|
||||
* AUX message. The sequence is slot 1-63 allocated sequence for each
|
||||
* stream. AMD ASIC stream slot allocation should follow the same
|
||||
* sequence. copy DRM MST allocation to dc */
|
||||
|
||||
get_payload_table(aconnector, proposed_table);
|
||||
fill_dc_mst_payload_table_from_drm(mst_state, aconnector, proposed_table);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -310,8 +277,9 @@ bool dm_helpers_dp_mst_send_payload_allocation(
|
||||
bool enable)
|
||||
{
|
||||
struct amdgpu_dm_connector *aconnector;
|
||||
struct drm_dp_mst_topology_state *mst_state;
|
||||
struct drm_dp_mst_topology_mgr *mst_mgr;
|
||||
struct drm_dp_mst_port *mst_port;
|
||||
struct drm_dp_mst_atomic_payload *payload;
|
||||
enum mst_progress_status set_flag = MST_ALLOCATE_NEW_PAYLOAD;
|
||||
enum mst_progress_status clr_flag = MST_CLEAR_ALLOCATED_PAYLOAD;
|
||||
|
||||
@ -320,19 +288,16 @@ bool dm_helpers_dp_mst_send_payload_allocation(
|
||||
if (!aconnector || !aconnector->mst_port)
|
||||
return false;
|
||||
|
||||
mst_port = aconnector->port;
|
||||
|
||||
mst_mgr = &aconnector->mst_port->mst_mgr;
|
||||
mst_state = to_drm_dp_mst_topology_state(mst_mgr->base.state);
|
||||
|
||||
if (!mst_mgr->mst_state)
|
||||
return false;
|
||||
|
||||
payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->port);
|
||||
if (!enable) {
|
||||
set_flag = MST_CLEAR_ALLOCATED_PAYLOAD;
|
||||
clr_flag = MST_ALLOCATE_NEW_PAYLOAD;
|
||||
}
|
||||
|
||||
if (drm_dp_update_payload_part2(mst_mgr)) {
|
||||
if (enable && drm_dp_add_payload_part2(mst_mgr, mst_state->base.state, payload)) {
|
||||
amdgpu_dm_set_mst_status(&aconnector->mst_status,
|
||||
set_flag, false);
|
||||
} else {
|
||||
@ -342,9 +307,6 @@ bool dm_helpers_dp_mst_send_payload_allocation(
|
||||
clr_flag, false);
|
||||
}
|
||||
|
||||
if (!enable)
|
||||
drm_dp_mst_deallocate_vcpi(mst_mgr, mst_port);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -447,34 +447,13 @@ dm_dp_mst_detect(struct drm_connector *connector,
|
||||
}
|
||||
|
||||
static int dm_dp_mst_atomic_check(struct drm_connector *connector,
|
||||
struct drm_atomic_state *state)
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
struct drm_connector_state *new_conn_state =
|
||||
drm_atomic_get_new_connector_state(state, connector);
|
||||
struct drm_connector_state *old_conn_state =
|
||||
drm_atomic_get_old_connector_state(state, connector);
|
||||
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
|
||||
struct drm_crtc_state *new_crtc_state;
|
||||
struct drm_dp_mst_topology_mgr *mst_mgr;
|
||||
struct drm_dp_mst_port *mst_port;
|
||||
struct drm_dp_mst_topology_mgr *mst_mgr = &aconnector->mst_port->mst_mgr;
|
||||
struct drm_dp_mst_port *mst_port = aconnector->port;
|
||||
|
||||
mst_port = aconnector->port;
|
||||
mst_mgr = &aconnector->mst_port->mst_mgr;
|
||||
|
||||
if (!old_conn_state->crtc)
|
||||
return 0;
|
||||
|
||||
if (new_conn_state->crtc) {
|
||||
new_crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc);
|
||||
if (!new_crtc_state ||
|
||||
!drm_atomic_crtc_needs_modeset(new_crtc_state) ||
|
||||
new_crtc_state->enable)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return drm_dp_atomic_release_vcpi_slots(state,
|
||||
mst_mgr,
|
||||
mst_port);
|
||||
return drm_dp_atomic_release_time_slots(state, mst_mgr, mst_port);
|
||||
}
|
||||
|
||||
static const struct drm_connector_helper_funcs dm_dp_mst_connector_helper_funcs = {
|
||||
@ -618,15 +597,8 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
|
||||
|
||||
dc_link_dp_get_max_link_enc_cap(aconnector->dc_link, &max_link_enc_cap);
|
||||
aconnector->mst_mgr.cbs = &dm_mst_cbs;
|
||||
drm_dp_mst_topology_mgr_init(
|
||||
&aconnector->mst_mgr,
|
||||
adev_to_drm(dm->adev),
|
||||
&aconnector->dm_dp_aux.aux,
|
||||
16,
|
||||
4,
|
||||
max_link_enc_cap.lane_count,
|
||||
drm_dp_bw_code_to_link_rate(max_link_enc_cap.link_rate),
|
||||
aconnector->connector_id);
|
||||
drm_dp_mst_topology_mgr_init(&aconnector->mst_mgr, adev_to_drm(dm->adev),
|
||||
&aconnector->dm_dp_aux.aux, 16, 4, aconnector->connector_id);
|
||||
|
||||
drm_connector_attach_dp_subconnector_property(&aconnector->base);
|
||||
}
|
||||
@ -731,6 +703,7 @@ static int bpp_x16_from_pbn(struct dsc_mst_fairness_params param, int pbn)
|
||||
}
|
||||
|
||||
static bool increase_dsc_bpp(struct drm_atomic_state *state,
|
||||
struct drm_dp_mst_topology_state *mst_state,
|
||||
struct dc_link *dc_link,
|
||||
struct dsc_mst_fairness_params *params,
|
||||
struct dsc_mst_fairness_vars *vars,
|
||||
@ -743,12 +716,9 @@ static bool increase_dsc_bpp(struct drm_atomic_state *state,
|
||||
int min_initial_slack;
|
||||
int next_index;
|
||||
int remaining_to_increase = 0;
|
||||
int pbn_per_timeslot;
|
||||
int link_timeslots_used;
|
||||
int fair_pbn_alloc;
|
||||
|
||||
pbn_per_timeslot = dm_mst_get_pbn_divider(dc_link);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (vars[i + k].dsc_enabled) {
|
||||
initial_slack[i] =
|
||||
@ -779,46 +749,43 @@ static bool increase_dsc_bpp(struct drm_atomic_state *state,
|
||||
link_timeslots_used = 0;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
link_timeslots_used += DIV_ROUND_UP(vars[i + k].pbn, pbn_per_timeslot);
|
||||
link_timeslots_used += DIV_ROUND_UP(vars[i + k].pbn, mst_state->pbn_div);
|
||||
|
||||
fair_pbn_alloc = (63 - link_timeslots_used) / remaining_to_increase * pbn_per_timeslot;
|
||||
fair_pbn_alloc =
|
||||
(63 - link_timeslots_used) / remaining_to_increase * mst_state->pbn_div;
|
||||
|
||||
if (initial_slack[next_index] > fair_pbn_alloc) {
|
||||
vars[next_index].pbn += fair_pbn_alloc;
|
||||
if (drm_dp_atomic_find_vcpi_slots(state,
|
||||
if (drm_dp_atomic_find_time_slots(state,
|
||||
params[next_index].port->mgr,
|
||||
params[next_index].port,
|
||||
vars[next_index].pbn,
|
||||
pbn_per_timeslot) < 0)
|
||||
vars[next_index].pbn) < 0)
|
||||
return false;
|
||||
if (!drm_dp_mst_atomic_check(state)) {
|
||||
vars[next_index].bpp_x16 = bpp_x16_from_pbn(params[next_index], vars[next_index].pbn);
|
||||
} else {
|
||||
vars[next_index].pbn -= fair_pbn_alloc;
|
||||
if (drm_dp_atomic_find_vcpi_slots(state,
|
||||
if (drm_dp_atomic_find_time_slots(state,
|
||||
params[next_index].port->mgr,
|
||||
params[next_index].port,
|
||||
vars[next_index].pbn,
|
||||
pbn_per_timeslot) < 0)
|
||||
vars[next_index].pbn) < 0)
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
vars[next_index].pbn += initial_slack[next_index];
|
||||
if (drm_dp_atomic_find_vcpi_slots(state,
|
||||
if (drm_dp_atomic_find_time_slots(state,
|
||||
params[next_index].port->mgr,
|
||||
params[next_index].port,
|
||||
vars[next_index].pbn,
|
||||
pbn_per_timeslot) < 0)
|
||||
vars[next_index].pbn) < 0)
|
||||
return false;
|
||||
if (!drm_dp_mst_atomic_check(state)) {
|
||||
vars[next_index].bpp_x16 = params[next_index].bw_range.max_target_bpp_x16;
|
||||
} else {
|
||||
vars[next_index].pbn -= initial_slack[next_index];
|
||||
if (drm_dp_atomic_find_vcpi_slots(state,
|
||||
if (drm_dp_atomic_find_time_slots(state,
|
||||
params[next_index].port->mgr,
|
||||
params[next_index].port,
|
||||
vars[next_index].pbn,
|
||||
pbn_per_timeslot) < 0)
|
||||
vars[next_index].pbn) < 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -872,11 +839,10 @@ static bool try_disable_dsc(struct drm_atomic_state *state,
|
||||
break;
|
||||
|
||||
vars[next_index].pbn = kbps_to_peak_pbn(params[next_index].bw_range.stream_kbps);
|
||||
if (drm_dp_atomic_find_vcpi_slots(state,
|
||||
if (drm_dp_atomic_find_time_slots(state,
|
||||
params[next_index].port->mgr,
|
||||
params[next_index].port,
|
||||
vars[next_index].pbn,
|
||||
dm_mst_get_pbn_divider(dc_link)) < 0)
|
||||
vars[next_index].pbn) < 0)
|
||||
return false;
|
||||
|
||||
if (!drm_dp_mst_atomic_check(state)) {
|
||||
@ -884,11 +850,10 @@ static bool try_disable_dsc(struct drm_atomic_state *state,
|
||||
vars[next_index].bpp_x16 = 0;
|
||||
} else {
|
||||
vars[next_index].pbn = kbps_to_peak_pbn(params[next_index].bw_range.max_kbps);
|
||||
if (drm_dp_atomic_find_vcpi_slots(state,
|
||||
if (drm_dp_atomic_find_time_slots(state,
|
||||
params[next_index].port->mgr,
|
||||
params[next_index].port,
|
||||
vars[next_index].pbn,
|
||||
dm_mst_get_pbn_divider(dc_link)) < 0)
|
||||
vars[next_index].pbn) < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -902,17 +867,27 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
|
||||
struct dc_state *dc_state,
|
||||
struct dc_link *dc_link,
|
||||
struct dsc_mst_fairness_vars *vars,
|
||||
struct drm_dp_mst_topology_mgr *mgr,
|
||||
int *link_vars_start_index)
|
||||
{
|
||||
int i, k;
|
||||
struct dc_stream_state *stream;
|
||||
struct dsc_mst_fairness_params params[MAX_PIPES];
|
||||
struct amdgpu_dm_connector *aconnector;
|
||||
struct drm_dp_mst_topology_state *mst_state = drm_atomic_get_mst_topology_state(state, mgr);
|
||||
int count = 0;
|
||||
int i, k;
|
||||
bool debugfs_overwrite = false;
|
||||
|
||||
memset(params, 0, sizeof(params));
|
||||
|
||||
if (IS_ERR(mst_state))
|
||||
return false;
|
||||
|
||||
mst_state->pbn_div = dm_mst_get_pbn_divider(dc_link);
|
||||
#if defined(CONFIG_DRM_AMD_DC_DCN)
|
||||
drm_dp_mst_update_slots(mst_state, dc_link_dp_mst_decide_link_encoding_format(dc_link));
|
||||
#endif
|
||||
|
||||
/* Set up params */
|
||||
for (i = 0; i < dc_state->stream_count; i++) {
|
||||
struct dc_dsc_policy dsc_policy = {0};
|
||||
@ -971,11 +946,8 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
|
||||
vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps);
|
||||
vars[i + k].dsc_enabled = false;
|
||||
vars[i + k].bpp_x16 = 0;
|
||||
if (drm_dp_atomic_find_vcpi_slots(state,
|
||||
params[i].port->mgr,
|
||||
params[i].port,
|
||||
vars[i + k].pbn,
|
||||
dm_mst_get_pbn_divider(dc_link)) < 0)
|
||||
if (drm_dp_atomic_find_time_slots(state, params[i].port->mgr, params[i].port,
|
||||
vars[i + k].pbn) < 0)
|
||||
return false;
|
||||
}
|
||||
if (!drm_dp_mst_atomic_check(state) && !debugfs_overwrite) {
|
||||
@ -989,21 +961,15 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
|
||||
vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.min_kbps);
|
||||
vars[i + k].dsc_enabled = true;
|
||||
vars[i + k].bpp_x16 = params[i].bw_range.min_target_bpp_x16;
|
||||
if (drm_dp_atomic_find_vcpi_slots(state,
|
||||
params[i].port->mgr,
|
||||
params[i].port,
|
||||
vars[i + k].pbn,
|
||||
dm_mst_get_pbn_divider(dc_link)) < 0)
|
||||
if (drm_dp_atomic_find_time_slots(state, params[i].port->mgr,
|
||||
params[i].port, vars[i + k].pbn) < 0)
|
||||
return false;
|
||||
} else {
|
||||
vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps);
|
||||
vars[i + k].dsc_enabled = false;
|
||||
vars[i + k].bpp_x16 = 0;
|
||||
if (drm_dp_atomic_find_vcpi_slots(state,
|
||||
params[i].port->mgr,
|
||||
params[i].port,
|
||||
vars[i + k].pbn,
|
||||
dm_mst_get_pbn_divider(dc_link)) < 0)
|
||||
if (drm_dp_atomic_find_time_slots(state, params[i].port->mgr,
|
||||
params[i].port, vars[i + k].pbn) < 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1011,7 +977,7 @@ static bool compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
|
||||
return false;
|
||||
|
||||
/* Optimize degree of compression */
|
||||
if (!increase_dsc_bpp(state, dc_link, params, vars, count, k))
|
||||
if (!increase_dsc_bpp(state, mst_state, dc_link, params, vars, count, k))
|
||||
return false;
|
||||
|
||||
if (!try_disable_dsc(state, dc_link, params, vars, count, k))
|
||||
@ -1157,8 +1123,9 @@ bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
|
||||
continue;
|
||||
|
||||
mutex_lock(&aconnector->mst_mgr.lock);
|
||||
if (!compute_mst_dsc_configs_for_link(state, dc_state, stream->link,
|
||||
vars, &link_vars_start_index)) {
|
||||
if (!compute_mst_dsc_configs_for_link(state, dc_state, stream->link, vars,
|
||||
&aconnector->mst_mgr,
|
||||
&link_vars_start_index)) {
|
||||
mutex_unlock(&aconnector->mst_mgr.lock);
|
||||
return false;
|
||||
}
|
||||
@ -1216,10 +1183,8 @@ static bool
|
||||
continue;
|
||||
|
||||
mutex_lock(&aconnector->mst_mgr.lock);
|
||||
if (!compute_mst_dsc_configs_for_link(state,
|
||||
dc_state,
|
||||
stream->link,
|
||||
vars,
|
||||
if (!compute_mst_dsc_configs_for_link(state, dc_state, stream->link, vars,
|
||||
&aconnector->mst_mgr,
|
||||
&link_vars_start_index)) {
|
||||
mutex_unlock(&aconnector->mst_mgr.lock);
|
||||
return false;
|
||||
|
@ -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,
|
||||
|
@ -3516,7 +3516,7 @@ static void update_mst_stream_alloc_table(
|
||||
struct dc_link *link,
|
||||
struct stream_encoder *stream_enc,
|
||||
struct hpo_dp_stream_encoder *hpo_dp_stream_enc, // TODO: Rename stream_enc to dio_stream_enc?
|
||||
const struct dp_mst_stream_allocation_table *proposed_table)
|
||||
const struct dc_dp_mst_stream_allocation_table *proposed_table)
|
||||
{
|
||||
struct link_mst_stream_allocation work_table[MAX_CONTROLLER_NUM] = { 0 };
|
||||
struct link_mst_stream_allocation *dc_alloc;
|
||||
@ -3679,7 +3679,7 @@ enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx)
|
||||
{
|
||||
struct dc_stream_state *stream = pipe_ctx->stream;
|
||||
struct dc_link *link = stream->link;
|
||||
struct dp_mst_stream_allocation_table proposed_table = {0};
|
||||
struct dc_dp_mst_stream_allocation_table proposed_table = {0};
|
||||
struct fixed31_32 avg_time_slots_per_mtp;
|
||||
struct fixed31_32 pbn;
|
||||
struct fixed31_32 pbn_per_slot;
|
||||
@ -3784,7 +3784,7 @@ enum dc_status dc_link_reduce_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t bw
|
||||
struct fixed31_32 avg_time_slots_per_mtp;
|
||||
struct fixed31_32 pbn;
|
||||
struct fixed31_32 pbn_per_slot;
|
||||
struct dp_mst_stream_allocation_table proposed_table = {0};
|
||||
struct dc_dp_mst_stream_allocation_table proposed_table = {0};
|
||||
uint8_t i;
|
||||
const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
|
||||
DC_LOGGER_INIT(link->ctx->logger);
|
||||
@ -3873,7 +3873,7 @@ enum dc_status dc_link_increase_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t
|
||||
struct fixed31_32 avg_time_slots_per_mtp;
|
||||
struct fixed31_32 pbn;
|
||||
struct fixed31_32 pbn_per_slot;
|
||||
struct dp_mst_stream_allocation_table proposed_table = {0};
|
||||
struct dc_dp_mst_stream_allocation_table proposed_table = {0};
|
||||
uint8_t i;
|
||||
enum act_return_status ret;
|
||||
const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
|
||||
@ -3957,7 +3957,7 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx)
|
||||
{
|
||||
struct dc_stream_state *stream = pipe_ctx->stream;
|
||||
struct dc_link *link = stream->link;
|
||||
struct dp_mst_stream_allocation_table proposed_table = {0};
|
||||
struct dc_dp_mst_stream_allocation_table proposed_table = {0};
|
||||
struct fixed31_32 avg_time_slots_per_mtp = dc_fixpt_from_int(0);
|
||||
int i;
|
||||
bool mst_mode = (link->type == dc_connection_mst_branch);
|
||||
|
@ -33,7 +33,7 @@
|
||||
#include "dc_types.h"
|
||||
#include "dc.h"
|
||||
|
||||
struct dp_mst_stream_allocation_table;
|
||||
struct dc_dp_mst_stream_allocation_table;
|
||||
struct aux_payload;
|
||||
enum aux_return_code_type;
|
||||
|
||||
@ -77,7 +77,7 @@ void dm_helpers_dp_update_branch_info(
|
||||
bool dm_helpers_dp_mst_write_payload_allocation_table(
|
||||
struct dc_context *ctx,
|
||||
const struct dc_stream_state *stream,
|
||||
struct dp_mst_stream_allocation_table *proposed_table,
|
||||
struct dc_dp_mst_stream_allocation_table *proposed_table,
|
||||
bool enable);
|
||||
|
||||
/*
|
||||
|
@ -246,8 +246,16 @@ union dpcd_training_lane_set {
|
||||
};
|
||||
|
||||
|
||||
/* AMD's copy of various payload data for MST. We have two copies of the payload table (one in DRM,
|
||||
* one in DC) since DRM's MST helpers can't be accessed here. This stream allocation table should
|
||||
* _ONLY_ be filled out from DM and then passed to DC, do NOT use these for _any_ kind of atomic
|
||||
* state calculations in DM, or you will break something.
|
||||
*/
|
||||
|
||||
struct drm_dp_mst_port;
|
||||
|
||||
/* DP MST stream allocation (payload bandwidth number) */
|
||||
struct dp_mst_stream_allocation {
|
||||
struct dc_dp_mst_stream_allocation {
|
||||
uint8_t vcp_id;
|
||||
/* number of slots required for the DP stream in
|
||||
* transport packet */
|
||||
@ -255,11 +263,11 @@ struct dp_mst_stream_allocation {
|
||||
};
|
||||
|
||||
/* DP MST stream allocation table */
|
||||
struct dp_mst_stream_allocation_table {
|
||||
struct dc_dp_mst_stream_allocation_table {
|
||||
/* number of DP video streams */
|
||||
int stream_count;
|
||||
/* array of stream allocations */
|
||||
struct dp_mst_stream_allocation stream_allocations[MAX_CONTROLLER_NUM];
|
||||
struct dc_dp_mst_stream_allocation stream_allocations[MAX_CONTROLLER_NUM];
|
||||
};
|
||||
|
||||
#endif /*__DAL_LINK_SERVICE_TYPES_H__*/
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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"
|
||||
|
@ -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]);
|
||||
|
@ -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)
|
||||
{
|
||||
struct hdlcd_drm_private *hdlcd = drm->dev_private;
|
||||
/* 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)
|
||||
static int hdlcd_irq_install(struct hdlcd_drm_private *hdlcd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (irq == IRQ_NOTCONNECTED)
|
||||
return -ENOTCONN;
|
||||
/* Ensure interrupts are disabled */
|
||||
hdlcd_write(hdlcd, HDLCD_REG_INT_MASK, 0);
|
||||
hdlcd_write(hdlcd, HDLCD_REG_INT_CLEAR, ~0);
|
||||
|
||||
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);
|
||||
hdlcd_write(hdlcd, HDLCD_REG_INT_MASK, 0);
|
||||
|
||||
#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);
|
||||
|
||||
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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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),
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -1440,6 +1440,20 @@ static void anx7625_start_dp_work(struct anx7625_data *ctx)
|
||||
|
||||
static int anx7625_read_hpd_status_p0(struct anx7625_data *ctx)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Set irq detect window to 2ms */
|
||||
ret = anx7625_reg_write(ctx, ctx->i2c.tx_p2_client,
|
||||
HPD_DET_TIMER_BIT0_7, HPD_TIME & 0xFF);
|
||||
ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client,
|
||||
HPD_DET_TIMER_BIT8_15,
|
||||
(HPD_TIME >> 8) & 0xFF);
|
||||
ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client,
|
||||
HPD_DET_TIMER_BIT16_23,
|
||||
(HPD_TIME >> 16) & 0xFF);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, SYSTEM_STSTUS);
|
||||
}
|
||||
|
||||
@ -1642,6 +1656,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");
|
||||
@ -1796,8 +1811,13 @@ static int anx7625_audio_hw_params(struct device *dev, void *data,
|
||||
int wl, ch, rate;
|
||||
int ret = 0;
|
||||
|
||||
if (fmt->fmt != HDMI_DSP_A) {
|
||||
DRM_DEV_ERROR(dev, "only supports DSP_A\n");
|
||||
if (anx7625_sink_detect(ctx) == connector_status_disconnected) {
|
||||
DRM_DEV_DEBUG_DRIVER(dev, "DP not connected\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fmt->fmt != HDMI_DSP_A && fmt->fmt != HDMI_I2S) {
|
||||
DRM_DEV_ERROR(dev, "only supports DSP_A & I2S\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -1805,10 +1825,16 @@ static int anx7625_audio_hw_params(struct device *dev, void *data,
|
||||
params->sample_rate, params->sample_width,
|
||||
params->cea.channels);
|
||||
|
||||
ret |= anx7625_write_and_or(ctx, ctx->i2c.tx_p2_client,
|
||||
AUDIO_CHANNEL_STATUS_6,
|
||||
~I2S_SLAVE_MODE,
|
||||
TDM_SLAVE_MODE);
|
||||
if (fmt->fmt == HDMI_DSP_A)
|
||||
ret = anx7625_write_and_or(ctx, ctx->i2c.tx_p2_client,
|
||||
AUDIO_CHANNEL_STATUS_6,
|
||||
~I2S_SLAVE_MODE,
|
||||
TDM_SLAVE_MODE);
|
||||
else
|
||||
ret = anx7625_write_and_or(ctx, ctx->i2c.tx_p2_client,
|
||||
AUDIO_CHANNEL_STATUS_6,
|
||||
~TDM_SLAVE_MODE,
|
||||
I2S_SLAVE_MODE);
|
||||
|
||||
/* Word length */
|
||||
switch (params->sample_width) {
|
||||
|
@ -132,6 +132,12 @@
|
||||
#define I2S_SLAVE_MODE 0x08
|
||||
#define AUDIO_LAYOUT 0x01
|
||||
|
||||
#define HPD_DET_TIMER_BIT0_7 0xea
|
||||
#define HPD_DET_TIMER_BIT8_15 0xeb
|
||||
#define HPD_DET_TIMER_BIT16_23 0xec
|
||||
/* HPD debounce time 2ms for 27M clock */
|
||||
#define HPD_TIME 54000
|
||||
|
||||
#define AUDIO_CONTROL_REGISTER 0xe6
|
||||
#define TDM_TIMING_MODE 0x08
|
||||
|
||||
|
@ -2605,7 +2605,8 @@ static int cdns_mhdp_remove(struct platform_device *pdev)
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
cancel_work_sync(&mhdp->modeset_retry_work);
|
||||
flush_scheduled_work();
|
||||
flush_work(&mhdp->hpd_work);
|
||||
/* Ignoring mhdp->hdcp.check_work and mhdp->hdcp.prop_work here. */
|
||||
|
||||
clk_disable_unprepare(mhdp->clk);
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
@ -151,6 +152,8 @@ struct chipone {
|
||||
struct regulator *vdd1;
|
||||
struct regulator *vdd2;
|
||||
struct regulator *vdd3;
|
||||
struct clk *refclk;
|
||||
unsigned long refclk_rate;
|
||||
bool interface_i2c;
|
||||
};
|
||||
|
||||
@ -259,7 +262,7 @@ static void chipone_configure_pll(struct chipone *icn,
|
||||
|
||||
/*
|
||||
* DSI byte clock frequency (input into PLL) is calculated as:
|
||||
* DSI_CLK = mode clock * bpp / dsi_data_lanes / 8
|
||||
* DSI_CLK = HS clock / 4
|
||||
*
|
||||
* DPI pixel clock frequency (output from PLL) is mode clock.
|
||||
*
|
||||
@ -273,8 +276,10 @@ static void chipone_configure_pll(struct chipone *icn,
|
||||
* It seems the PLL input clock after applying P pre-divider have
|
||||
* to be lower than 20 MHz.
|
||||
*/
|
||||
fin = mode_clock * mipi_dsi_pixel_format_to_bpp(icn->dsi->format) /
|
||||
icn->dsi->lanes / 8; /* in Hz */
|
||||
if (icn->refclk)
|
||||
fin = icn->refclk_rate;
|
||||
else
|
||||
fin = icn->dsi->hs_rate / 4; /* in Hz */
|
||||
|
||||
/* Minimum value of P predivider for PLL input in 5..20 MHz */
|
||||
p_min = clamp(DIV_ROUND_UP(fin, 20000000), 1U, 31U);
|
||||
@ -319,16 +324,18 @@ static void chipone_configure_pll(struct chipone *icn,
|
||||
best_p_pot = !(best_p & 1);
|
||||
|
||||
dev_dbg(icn->dev,
|
||||
"PLL: P[3:0]=%d P[4]=2*%d M=%d S[7:5]=2^%d delta=%d => DSI f_in=%d Hz ; DPI f_out=%d Hz\n",
|
||||
"PLL: P[3:0]=%d P[4]=2*%d M=%d S[7:5]=2^%d delta=%d => DSI f_in(%s)=%d Hz ; DPI f_out=%d Hz\n",
|
||||
best_p >> best_p_pot, best_p_pot, best_m, best_s + 1,
|
||||
min_delta, fin, (fin * best_m) / (best_p << (best_s + 1)));
|
||||
min_delta, icn->refclk ? "EXT" : "DSI", fin,
|
||||
(fin * best_m) / (best_p << (best_s + 1)));
|
||||
|
||||
ref_div = PLL_REF_DIV_P(best_p >> best_p_pot) | PLL_REF_DIV_S(best_s);
|
||||
if (best_p_pot) /* Prefer /2 pre-divider */
|
||||
ref_div |= PLL_REF_DIV_Pe;
|
||||
|
||||
/* Clock source selection fixed to MIPI DSI clock lane */
|
||||
chipone_writeb(icn, PLL_CTRL(6), PLL_CTRL_6_MIPI_CLK);
|
||||
/* Clock source selection either external clock or MIPI DSI clock lane */
|
||||
chipone_writeb(icn, PLL_CTRL(6),
|
||||
icn->refclk ? PLL_CTRL_6_EXTERNAL : PLL_CTRL_6_MIPI_CLK);
|
||||
chipone_writeb(icn, PLL_REF_DIV, ref_div);
|
||||
chipone_writeb(icn, PLL_INT(0), best_m);
|
||||
}
|
||||
@ -464,6 +471,11 @@ static void chipone_atomic_pre_enable(struct drm_bridge *bridge,
|
||||
"failed to enable VDD3 regulator: %d\n", ret);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(icn->refclk);
|
||||
if (ret)
|
||||
DRM_DEV_ERROR(icn->dev,
|
||||
"failed to enable RECLK clock: %d\n", ret);
|
||||
|
||||
gpiod_set_value(icn->enable_gpio, 1);
|
||||
|
||||
usleep_range(10000, 11000);
|
||||
@ -474,6 +486,8 @@ static void chipone_atomic_post_disable(struct drm_bridge *bridge,
|
||||
{
|
||||
struct chipone *icn = bridge_to_chipone(bridge);
|
||||
|
||||
clk_disable_unprepare(icn->refclk);
|
||||
|
||||
if (icn->vdd1)
|
||||
regulator_disable(icn->vdd1);
|
||||
|
||||
@ -515,6 +529,8 @@ static int chipone_dsi_attach(struct chipone *icn)
|
||||
dsi->format = MIPI_DSI_FMT_RGB888;
|
||||
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
|
||||
MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET;
|
||||
dsi->hs_rate = 500000000;
|
||||
dsi->lp_rate = 16000000;
|
||||
|
||||
ret = mipi_dsi_attach(dsi);
|
||||
if (ret < 0)
|
||||
@ -617,6 +633,20 @@ static int chipone_parse_dt(struct chipone *icn)
|
||||
struct device *dev = icn->dev;
|
||||
int ret;
|
||||
|
||||
icn->refclk = devm_clk_get_optional(dev, "refclk");
|
||||
if (IS_ERR(icn->refclk)) {
|
||||
ret = PTR_ERR(icn->refclk);
|
||||
DRM_DEV_ERROR(dev, "failed to get REFCLK clock: %d\n", ret);
|
||||
return ret;
|
||||
} else if (icn->refclk) {
|
||||
icn->refclk_rate = clk_get_rate(icn->refclk);
|
||||
if (icn->refclk_rate < 10000000 || icn->refclk_rate > 154000000) {
|
||||
DRM_DEV_ERROR(dev, "REFCLK out of range: %ld Hz\n",
|
||||
icn->refclk_rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
icn->vdd1 = devm_regulator_get_optional(dev, "vdd1");
|
||||
if (IS_ERR(icn->vdd1)) {
|
||||
ret = PTR_ERR(icn->vdd1);
|
||||
@ -735,14 +765,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[] = {
|
||||
|
@ -68,6 +68,7 @@ enum {
|
||||
BYTE_SWAP_GBR = 3,
|
||||
BYTE_SWAP_BRG = 4,
|
||||
BYTE_SWAP_BGR = 5,
|
||||
BYTE_SWAP_MAX = 6,
|
||||
};
|
||||
|
||||
/* Page 0, Register 0x19 */
|
||||
@ -355,6 +356,8 @@ static void ch7033_bridge_mode_set(struct drm_bridge *bridge,
|
||||
int hsynclen = mode->hsync_end - mode->hsync_start;
|
||||
int vbporch = mode->vsync_start - mode->vdisplay;
|
||||
int vsynclen = mode->vsync_end - mode->vsync_start;
|
||||
u8 byte_swap;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Page 4
|
||||
@ -398,8 +401,16 @@ static void ch7033_bridge_mode_set(struct drm_bridge *bridge,
|
||||
regmap_write(priv->regmap, 0x15, vbporch);
|
||||
regmap_write(priv->regmap, 0x16, vsynclen);
|
||||
|
||||
/* Input color swap. */
|
||||
regmap_update_bits(priv->regmap, 0x18, SWAP, BYTE_SWAP_BGR);
|
||||
/* Input color swap. Byte order is optional and will default to
|
||||
* BYTE_SWAP_BGR to preserve backwards compatibility with existing
|
||||
* driver.
|
||||
*/
|
||||
ret = of_property_read_u8(priv->bridge.of_node, "chrontel,byteswap",
|
||||
&byte_swap);
|
||||
if (!ret && byte_swap < BYTE_SWAP_MAX)
|
||||
regmap_update_bits(priv->regmap, 0x18, SWAP, byte_swap);
|
||||
else
|
||||
regmap_update_bits(priv->regmap, 0x18, SWAP, BYTE_SWAP_BGR);
|
||||
|
||||
/* Input clock and sync polarity. */
|
||||
regmap_update_bits(priv->regmap, 0x19, 0x1, mode->clock >> 16);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
@ -2954,6 +2960,9 @@ static void it6505_bridge_atomic_enable(struct drm_bridge *bridge,
|
||||
|
||||
it6505_int_mask_enable(it6505);
|
||||
it6505_video_reset(it6505);
|
||||
|
||||
it6505_drm_dp_link_set_power(&it6505->aux, &it6505->link,
|
||||
DP_SET_POWER_D0);
|
||||
}
|
||||
|
||||
static void it6505_bridge_atomic_disable(struct drm_bridge *bridge,
|
||||
@ -2965,9 +2974,9 @@ static void it6505_bridge_atomic_disable(struct drm_bridge *bridge,
|
||||
DRM_DEV_DEBUG_DRIVER(dev, "start");
|
||||
|
||||
if (it6505->powered) {
|
||||
it6505_video_disable(it6505);
|
||||
it6505_drm_dp_link_set_power(&it6505->aux, &it6505->link,
|
||||
DP_SET_POWER_D3);
|
||||
it6505_video_disable(it6505);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -296,7 +296,9 @@ static void ge_b850v3_lvds_remove(void)
|
||||
* This check is to avoid both the drivers
|
||||
* removing the bridge in their remove() function
|
||||
*/
|
||||
if (!ge_b850v3_lvds_ptr)
|
||||
if (!ge_b850v3_lvds_ptr ||
|
||||
!ge_b850v3_lvds_ptr->stdp2690_i2c ||
|
||||
!ge_b850v3_lvds_ptr->stdp4028_i2c)
|
||||
goto out;
|
||||
|
||||
drm_bridge_remove(&ge_b850v3_lvds_ptr->bridge);
|
||||
|
@ -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
|
||||
|
@ -375,6 +375,11 @@ static int __maybe_unused ps8640_resume(struct device *dev)
|
||||
gpiod_set_value(ps_bridge->gpio_reset, 1);
|
||||
usleep_range(2000, 2500);
|
||||
gpiod_set_value(ps_bridge->gpio_reset, 0);
|
||||
/* Double reset for T4 and T5 */
|
||||
msleep(50);
|
||||
gpiod_set_value(ps_bridge->gpio_reset, 1);
|
||||
msleep(50);
|
||||
gpiod_set_value(ps_bridge->gpio_reset, 0);
|
||||
|
||||
/*
|
||||
* Mystery 200 ms delay for the "MCU to be ready". It's unclear if
|
||||
@ -631,8 +636,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)
|
||||
|
@ -3096,6 +3096,7 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct dw_hdmi *hdmi = dev_id;
|
||||
u8 intr_stat, phy_int_pol, phy_pol_mask, phy_stat;
|
||||
enum drm_connector_status status = connector_status_unknown;
|
||||
|
||||
intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
|
||||
phy_int_pol = hdmi_readb(hdmi, HDMI_PHY_POL0);
|
||||
@ -3134,13 +3135,15 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
|
||||
cec_notifier_phys_addr_invalidate(hdmi->cec_notifier);
|
||||
mutex_unlock(&hdmi->cec_notifier_mutex);
|
||||
}
|
||||
|
||||
if (phy_stat & HDMI_PHY_HPD)
|
||||
status = connector_status_connected;
|
||||
|
||||
if (!(phy_stat & (HDMI_PHY_HPD | HDMI_PHY_RX_SENSE)))
|
||||
status = connector_status_disconnected;
|
||||
}
|
||||
|
||||
if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
|
||||
enum drm_connector_status status = phy_int_pol & HDMI_PHY_HPD
|
||||
? connector_status_connected
|
||||
: connector_status_disconnected;
|
||||
|
||||
if (status != connector_status_unknown) {
|
||||
dev_dbg(hdmi->dev, "EVENT=%s\n",
|
||||
status == connector_status_connected ?
|
||||
"plugin" : "plugout");
|
||||
|
@ -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[] = {
|
||||
|
@ -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[] = {
|
||||
|
@ -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,
|
||||
@ -1925,22 +1913,23 @@ static int tc_mipi_dsi_host_attach(struct tc_data *tc)
|
||||
static int tc_probe_dpi_bridge_endpoint(struct tc_data *tc)
|
||||
{
|
||||
struct device *dev = tc->dev;
|
||||
struct drm_bridge *bridge;
|
||||
struct drm_panel *panel;
|
||||
int ret;
|
||||
|
||||
/* port@1 is the DPI input/output port */
|
||||
ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL);
|
||||
ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, &bridge);
|
||||
if (ret && ret != -ENODEV)
|
||||
return ret;
|
||||
|
||||
if (panel) {
|
||||
struct drm_bridge *panel_bridge;
|
||||
bridge = devm_drm_panel_bridge_add(dev, panel);
|
||||
if (IS_ERR(bridge))
|
||||
return PTR_ERR(bridge);
|
||||
}
|
||||
|
||||
panel_bridge = devm_drm_panel_bridge_add(dev, panel);
|
||||
if (IS_ERR(panel_bridge))
|
||||
return PTR_ERR(panel_bridge);
|
||||
|
||||
tc->panel_bridge = panel_bridge;
|
||||
if (bridge) {
|
||||
tc->panel_bridge = bridge;
|
||||
tc->bridge.type = DRM_MODE_CONNECTOR_DPI;
|
||||
tc->bridge.funcs = &tc_dpi_bridge_funcs;
|
||||
|
||||
@ -2010,9 +1999,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);
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_bridge_connector.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_panel.h>
|
||||
@ -68,6 +69,7 @@
|
||||
#define BPP_18_RGB BIT(0)
|
||||
#define SN_HPD_DISABLE_REG 0x5C
|
||||
#define HPD_DISABLE BIT(0)
|
||||
#define HPD_DEBOUNCED_STATE BIT(4)
|
||||
#define SN_GPIO_IO_REG 0x5E
|
||||
#define SN_GPIO_INPUT_SHIFT 4
|
||||
#define SN_GPIO_OUTPUT_SHIFT 0
|
||||
@ -92,6 +94,8 @@
|
||||
#define SN_DATARATE_CONFIG_REG 0x94
|
||||
#define DP_DATARATE_MASK GENMASK(7, 5)
|
||||
#define DP_DATARATE(x) ((x) << 5)
|
||||
#define SN_TRAINING_SETTING_REG 0x95
|
||||
#define SCRAMBLE_DISABLE BIT(4)
|
||||
#define SN_ML_TX_MODE_REG 0x96
|
||||
#define ML_TX_MAIN_LINK_OFF 0
|
||||
#define ML_TX_NORMAL_MODE BIT(0)
|
||||
@ -698,11 +702,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 +709,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)) {
|
||||
@ -749,6 +751,29 @@ ti_sn_bridge_mode_valid(struct drm_bridge *bridge,
|
||||
if (mode->clock > 594000)
|
||||
return MODE_CLOCK_HIGH;
|
||||
|
||||
/*
|
||||
* The front and back porch registers are 8 bits, and pulse width
|
||||
* registers are 15 bits, so reject any modes with larger periods.
|
||||
*/
|
||||
|
||||
if ((mode->hsync_start - mode->hdisplay) > 0xff)
|
||||
return MODE_HBLANK_WIDE;
|
||||
|
||||
if ((mode->vsync_start - mode->vdisplay) > 0xff)
|
||||
return MODE_VBLANK_WIDE;
|
||||
|
||||
if ((mode->hsync_end - mode->hsync_start) > 0x7fff)
|
||||
return MODE_HSYNC_WIDE;
|
||||
|
||||
if ((mode->vsync_end - mode->vsync_start) > 0x7fff)
|
||||
return MODE_VSYNC_WIDE;
|
||||
|
||||
if ((mode->htotal - mode->hsync_end) > 0xff)
|
||||
return MODE_HBLANK_WIDE;
|
||||
|
||||
if ((mode->vtotal - mode->vsync_end) > 0xff)
|
||||
return MODE_VBLANK_WIDE;
|
||||
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
@ -779,9 +804,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 +821,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 +829,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 +1041,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);
|
||||
@ -1040,15 +1074,27 @@ static void ti_sn_bridge_atomic_enable(struct drm_bridge *bridge,
|
||||
|
||||
/*
|
||||
* The SN65DSI86 only supports ASSR Display Authentication method and
|
||||
* this method is enabled by default. An eDP panel must support this
|
||||
* this method is enabled for eDP panels. An eDP panel must support this
|
||||
* authentication method. We need to enable this method in the eDP panel
|
||||
* at DisplayPort address 0x0010A prior to link training.
|
||||
*
|
||||
* As only ASSR is supported by SN65DSI86, for full DisplayPort displays
|
||||
* we need to disable the scrambler.
|
||||
*/
|
||||
drm_dp_dpcd_writeb(&pdata->aux, DP_EDP_CONFIGURATION_SET,
|
||||
DP_ALTERNATE_SCRAMBLER_RESET_ENABLE);
|
||||
if (pdata->bridge.type == DRM_MODE_CONNECTOR_eDP) {
|
||||
drm_dp_dpcd_writeb(&pdata->aux, DP_EDP_CONFIGURATION_SET,
|
||||
DP_ALTERNATE_SCRAMBLER_RESET_ENABLE);
|
||||
|
||||
regmap_update_bits(pdata->regmap, SN_TRAINING_SETTING_REG,
|
||||
SCRAMBLE_DISABLE, 0);
|
||||
} else {
|
||||
regmap_update_bits(pdata->regmap, SN_TRAINING_SETTING_REG,
|
||||
SCRAMBLE_DISABLE, SCRAMBLE_DISABLE);
|
||||
}
|
||||
|
||||
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 +1105,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)))
|
||||
@ -1114,10 +1160,33 @@ static void ti_sn_bridge_atomic_post_disable(struct drm_bridge *bridge,
|
||||
pm_runtime_put_sync(pdata->dev);
|
||||
}
|
||||
|
||||
static enum drm_connector_status ti_sn_bridge_detect(struct drm_bridge *bridge)
|
||||
{
|
||||
struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge);
|
||||
int val = 0;
|
||||
|
||||
pm_runtime_get_sync(pdata->dev);
|
||||
regmap_read(pdata->regmap, SN_HPD_DISABLE_REG, &val);
|
||||
pm_runtime_put_autosuspend(pdata->dev);
|
||||
|
||||
return val & HPD_DEBOUNCED_STATE ? connector_status_connected
|
||||
: connector_status_disconnected;
|
||||
}
|
||||
|
||||
static struct edid *ti_sn_bridge_get_edid(struct drm_bridge *bridge,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge);
|
||||
|
||||
return drm_get_edid(connector, &pdata->aux.ddc);
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs ti_sn_bridge_funcs = {
|
||||
.attach = ti_sn_bridge_attach,
|
||||
.detach = ti_sn_bridge_detach,
|
||||
.mode_valid = ti_sn_bridge_mode_valid,
|
||||
.get_edid = ti_sn_bridge_get_edid,
|
||||
.detect = ti_sn_bridge_detect,
|
||||
.atomic_pre_enable = ti_sn_bridge_atomic_pre_enable,
|
||||
.atomic_enable = ti_sn_bridge_atomic_enable,
|
||||
.atomic_disable = ti_sn_bridge_atomic_disable,
|
||||
@ -1198,10 +1267,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);
|
||||
|
||||
@ -1211,6 +1279,11 @@ static int ti_sn_bridge_probe(struct auxiliary_device *adev,
|
||||
|
||||
pdata->bridge.funcs = &ti_sn_bridge_funcs;
|
||||
pdata->bridge.of_node = np;
|
||||
pdata->bridge.type = pdata->next_bridge->type == DRM_MODE_CONNECTOR_DisplayPort
|
||||
? DRM_MODE_CONNECTOR_DisplayPort : DRM_MODE_CONNECTOR_eDP;
|
||||
|
||||
if (pdata->bridge.type == DRM_MODE_CONNECTOR_DisplayPort)
|
||||
pdata->bridge.ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT;
|
||||
|
||||
drm_bridge_add(&pdata->bridge);
|
||||
|
||||
|
@ -390,6 +390,38 @@ void drm_dp_link_train_channel_eq_delay(const struct drm_dp_aux *aux,
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_link_train_channel_eq_delay);
|
||||
|
||||
/**
|
||||
* drm_dp_phy_name() - Get the name of the given DP PHY
|
||||
* @dp_phy: The DP PHY identifier
|
||||
*
|
||||
* Given the @dp_phy, get a user friendly name of the DP PHY, either "DPRX" or
|
||||
* "LTTPR <N>", or "<INVALID DP PHY>" on errors. The returned string is always
|
||||
* non-NULL and valid.
|
||||
*
|
||||
* Returns: Name of the DP PHY.
|
||||
*/
|
||||
const char *drm_dp_phy_name(enum drm_dp_phy dp_phy)
|
||||
{
|
||||
static const char * const phy_names[] = {
|
||||
[DP_PHY_DPRX] = "DPRX",
|
||||
[DP_PHY_LTTPR1] = "LTTPR 1",
|
||||
[DP_PHY_LTTPR2] = "LTTPR 2",
|
||||
[DP_PHY_LTTPR3] = "LTTPR 3",
|
||||
[DP_PHY_LTTPR4] = "LTTPR 4",
|
||||
[DP_PHY_LTTPR5] = "LTTPR 5",
|
||||
[DP_PHY_LTTPR6] = "LTTPR 6",
|
||||
[DP_PHY_LTTPR7] = "LTTPR 7",
|
||||
[DP_PHY_LTTPR8] = "LTTPR 8",
|
||||
};
|
||||
|
||||
if (dp_phy < 0 || dp_phy >= ARRAY_SIZE(phy_names) ||
|
||||
WARN_ON(!phy_names[dp_phy]))
|
||||
return "<INVALID DP PHY>";
|
||||
|
||||
return phy_names[dp_phy];
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_phy_name);
|
||||
|
||||
void drm_dp_lttpr_link_train_clock_recovery_delay(void)
|
||||
{
|
||||
usleep_range(100, 200);
|
||||
@ -1597,7 +1629,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
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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>
|
||||
@ -703,8 +702,12 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
|
||||
|
||||
if (funcs->atomic_check)
|
||||
ret = funcs->atomic_check(connector, state);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
drm_dbg_atomic(dev,
|
||||
"[CONNECTOR:%d:%s] driver check failed\n",
|
||||
connector->base.id, connector->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
connectors_mask |= BIT(i);
|
||||
}
|
||||
@ -746,8 +749,12 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
|
||||
|
||||
if (funcs->atomic_check)
|
||||
ret = funcs->atomic_check(connector, state);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
drm_dbg_atomic(dev,
|
||||
"[CONNECTOR:%d:%s] driver check failed\n",
|
||||
connector->base.id, connector->name);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -778,6 +785,45 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_helper_check_modeset);
|
||||
|
||||
/**
|
||||
* drm_atomic_helper_check_wb_connector_state() - Check writeback encoder state
|
||||
* @encoder: encoder state to check
|
||||
* @conn_state: connector state to check
|
||||
*
|
||||
* Checks if the writeback connector state is valid, and returns an error if it
|
||||
* isn't.
|
||||
*
|
||||
* RETURNS:
|
||||
* Zero for success or -errno
|
||||
*/
|
||||
int
|
||||
drm_atomic_helper_check_wb_encoder_state(struct drm_encoder *encoder,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_writeback_job *wb_job = conn_state->writeback_job;
|
||||
struct drm_property_blob *pixel_format_blob;
|
||||
struct drm_framebuffer *fb;
|
||||
size_t i, nformats;
|
||||
u32 *formats;
|
||||
|
||||
if (!wb_job || !wb_job->fb)
|
||||
return 0;
|
||||
|
||||
pixel_format_blob = wb_job->connector->pixel_formats_blob_ptr;
|
||||
nformats = pixel_format_blob->length / sizeof(u32);
|
||||
formats = pixel_format_blob->data;
|
||||
fb = wb_job->fb;
|
||||
|
||||
for (i = 0; i < nformats; i++)
|
||||
if (fb->format->format == formats[i])
|
||||
return 0;
|
||||
|
||||
drm_dbg_kms(encoder->dev, "Invalid pixel format %p4cc\n", &fb->format->format);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_helper_check_wb_encoder_state);
|
||||
|
||||
/**
|
||||
* drm_atomic_helper_check_plane_state() - Check plane state for validity
|
||||
* @plane_state: plane state to check
|
||||
@ -1789,7 +1835,7 @@ int drm_atomic_helper_async_check(struct drm_device *dev,
|
||||
struct drm_plane_state *old_plane_state = NULL;
|
||||
struct drm_plane_state *new_plane_state = NULL;
|
||||
const struct drm_plane_helper_funcs *funcs;
|
||||
int i, n_planes = 0;
|
||||
int i, ret, n_planes = 0;
|
||||
|
||||
for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
|
||||
if (drm_atomic_crtc_needs_modeset(crtc_state))
|
||||
@ -1800,19 +1846,34 @@ int drm_atomic_helper_async_check(struct drm_device *dev,
|
||||
n_planes++;
|
||||
|
||||
/* FIXME: we support only single plane updates for now */
|
||||
if (n_planes != 1)
|
||||
if (n_planes != 1) {
|
||||
drm_dbg_atomic(dev,
|
||||
"only single plane async updates are supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!new_plane_state->crtc ||
|
||||
old_plane_state->crtc != new_plane_state->crtc)
|
||||
old_plane_state->crtc != new_plane_state->crtc) {
|
||||
drm_dbg_atomic(dev,
|
||||
"[PLANE:%d:%s] async update cannot change CRTC\n",
|
||||
plane->base.id, plane->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
funcs = plane->helper_private;
|
||||
if (!funcs->atomic_async_update)
|
||||
if (!funcs->atomic_async_update) {
|
||||
drm_dbg_atomic(dev,
|
||||
"[PLANE:%d:%s] driver does not support async updates\n",
|
||||
plane->base.id, plane->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (new_plane_state->fence)
|
||||
if (new_plane_state->fence) {
|
||||
drm_dbg_atomic(dev,
|
||||
"[PLANE:%d:%s] missing fence for async update\n",
|
||||
plane->base.id, plane->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't do an async update if there is an outstanding commit modifying
|
||||
@ -1827,7 +1888,12 @@ int drm_atomic_helper_async_check(struct drm_device *dev,
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return funcs->atomic_async_check(plane, state);
|
||||
ret = funcs->atomic_async_check(plane, state);
|
||||
if (ret != 0)
|
||||
drm_dbg_atomic(dev,
|
||||
"[PLANE:%d:%s] driver async check failed\n",
|
||||
plane->base.id, plane->name);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_helper_async_check);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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_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_managed.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_print.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.
|
||||
*/
|
||||
@ -357,19 +389,64 @@ int drm_connector_init_with_ddc(struct drm_device *dev,
|
||||
const struct drm_connector_funcs *funcs,
|
||||
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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
@ -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);
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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,66 +129,83 @@ static int drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsigned
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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))
|
||||
{
|
||||
static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = {
|
||||
0, 0, 0, 0
|
||||
};
|
||||
|
||||
if (!dst_pitch)
|
||||
dst_pitch = default_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);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_fb_memcpy - Copy clip buffer
|
||||
* @dst: Destination buffer
|
||||
* @dst_pitch: Number of bytes between two consecutive scanlines within dst
|
||||
* @vaddr: 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
|
||||
*
|
||||
* 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(void *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
|
||||
};
|
||||
|
||||
const struct drm_format_info *format = fb->format;
|
||||
unsigned int i, y, lines = drm_rect_height(clip);
|
||||
|
||||
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;
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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_toio(void __iomem *dst, unsigned int dst_pitch, const void *vaddr,
|
||||
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;
|
||||
|
||||
if (!dst_pitch)
|
||||
dst_pitch = len;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_memcpy_toio);
|
||||
|
||||
static void drm_fb_swab16_line(void *dbuf, const void *sbuf, unsigned int pixels)
|
||||
{
|
||||
u16 *dbuf16 = dbuf;
|
||||
@ -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.
|
||||
* 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 RGB565 devices that don't support XRGB8888 natively.
|
||||
*/
|
||||
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)
|
||||
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(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(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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* Drivers can use this function for RGB565 devices that don't natively
|
||||
* support XRGB8888.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
if (swab)
|
||||
drm_fb_xfrm_toio(dst, dst_pitch, 2, vaddr, fb, clip, false,
|
||||
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);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565_toio);
|
||||
|
||||
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
|
||||
*
|
||||
* 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(void *dst, unsigned int dst_pitch, const void *src,
|
||||
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(dst, dst_pitch, 3, src, 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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
drm_fb_xfrm_toio(dst, dst_pitch, 3, vaddr, fb, clip, false,
|
||||
drm_fb_xrgb8888_to_rgb888_line);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888_toio);
|
||||
|
||||
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);
|
||||
|
@ -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 },
|
||||
@ -370,6 +404,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
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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");
|
@ -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,
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user