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:
Jani Nikula 2022-09-12 11:11:02 +03:00
commit 6f3562b3bc
545 changed files with 22109 additions and 17522 deletions

View File

@ -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.

View File

@ -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

View File

@ -17,6 +17,8 @@ properties:
enum:
- ingenic,jz4740-lcd
- ingenic,jz4725b-lcd
- ingenic,jz4760-lcd
- ingenic,jz4760b-lcd
- ingenic,jz4770-lcd
- ingenic,jz4780-lcd

View File

@ -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>;
};
};
};
};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
----------------------

View File

@ -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.

View File

@ -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

View File

@ -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);

View File

@ -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,

View File

@ -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";

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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
};

View File

@ -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);

View File

@ -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>

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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
};

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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,

View File

@ -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);

View File

@ -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);
/*

View File

@ -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__*/

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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)
{

View File

@ -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;

View File

@ -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 */

View File

@ -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);

View File

@ -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);

View File

@ -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.

View File

@ -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"

View File

@ -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]);

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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

View File

@ -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)

View File

@ -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",

View File

@ -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;

View File

@ -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

View File

@ -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",

View File

@ -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),

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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) {

View File

@ -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

View File

@ -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);

View File

@ -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[] = {

View File

@ -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);

View File

@ -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);

View File

@ -813,13 +813,14 @@ static int lt9611_connector_init(struct drm_bridge *bridge, struct lt9611 *lt961
drm_connector_helper_add(&lt9611->connector,
&lt9611_bridge_connector_helper_funcs);
drm_connector_attach_encoder(&lt9611->connector, bridge->encoder);
if (!bridge->encoder) {
DRM_ERROR("Parent encoder object not found");
return -ENODEV;
}
drm_connector_attach_encoder(&lt9611->connector, bridge->encoder);
return 0;
}

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -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");

View File

@ -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[] = {

View File

@ -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[] = {

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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)
{

View File

@ -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);

View File

@ -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>

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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 */

View File

@ -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);

View File

@ -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

View File

@ -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.
*/

View File

@ -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");

View File

@ -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,

View File

@ -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)
{

View File

@ -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);

View File

@ -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);

View File

@ -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