Merge tag 'drm-misc-next-2026-08-06' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next

drm-misc-next for v7.3:

UAPI Changes:
- Remove the default udmabuf size limit of 64MB.

Cross-subsystem Changes:
- Add dmemcg support for eviction, and hook it up for amdgpu and xe.

Core Changes:
- Changes to TTM to be more aggressive when allocating below protection limit!
- Improve dt binding documentation for renesas.
- Add helper to convert physical address back to buddy block,
  add that to and improve its kunit test.

Driver Changes:
- Assorted small fixes to ti-sn65dsi86, panthor, imagination, omapdrm,
  bridge/synopsys, panel-edp, ssd130x, panel/tdo-tl070wsh30.
- Add Sharp LQ120P1JX51 panel.
- Add dmemcg support to nouveau.
- Various updates and improvements to sun4i, among which YUV and 4k support.

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patch.msgid.link/917d462a-8976-4a15-bec4-4513ec51c5c0@linux.intel.com
This commit is contained in:
Dave Airlie
2026-08-08 14:13:33 +10:00
113 changed files with 2261 additions and 558 deletions

View File

@@ -28,6 +28,7 @@ properties:
- const: renesas,r9a09g057-mipi-dsi
- enum:
- renesas,r9a08g046-mipi-dsi # RZ/G3L
- renesas,r9a09g057-mipi-dsi # RZ/V2H(P)
reg:

View File

@@ -0,0 +1,120 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/bridge/renesas,r9a08g046-lvds.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas RZ/G3L LVDS Encoder
maintainers:
- Biju Das <biju.das.jz@bp.renesas.com>
- Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
description: |
This binding describes the LVDS encoder embedded in the Renesas RZ/G3L
SoC. The encoder can operate in LVDS Single-link mode with 4 lanes
(Data) + 1 lane (Clock).
properties:
compatible:
const: renesas,r9a08g046-lvds
reg:
maxItems: 1
clocks:
items:
- description: Peripheral clock
- description: PHY clock
- description: Dot clock
clock-names:
items:
- const: pclk
- const: phyclk
- const: dotclk
resets:
items:
- description: LVDS_RESET_N
- description: MIPI_DSI_PRESET_N
- description: MIPI_DSI_CMN_RSTB
- description: MIPI_DSI_ARESET_N
reset-names:
items:
- const: lvdrst
- const: prst
- const: rst
- const: arst
power-domains:
maxItems: 1
ports:
$ref: /schemas/graph.yaml#/properties/ports
properties:
port@0:
$ref: /schemas/graph.yaml#/properties/port
description: Input channel, directly connected to the Display Unit.
port@1:
$ref: /schemas/graph.yaml#/properties/port
description: |
Output channel, directly connected to the LVDS panel or bridge.
required:
- port@0
- port@1
required:
- compatible
- reg
- clocks
- clock-names
- resets
- reset-names
- power-domains
- ports
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/renesas,r9a08g046-cpg.h>
lvds@108a0000 {
compatible = "renesas,r9a08g046-lvds";
reg = <0x108a0000 0x10000>;
clocks = <&cpg CPG_MOD R9A08G046_MIPI_DSI_PCLK>,
<&cpg CPG_MOD R9A08G046_LVDS_PLLCLK>,
<&cpg CPG_MOD R9A08G046_LVDS_CLK_DOT0>;
clock-names = "pclk", "phyclk", "dotclk";
resets = <&cpg R9A08G046_LVDS_RESET_N>,
<&cpg R9A08G046_MIPI_DSI_PRESET_N>,
<&cpg R9A08G046_MIPI_DSI_CMN_RSTB>,
<&cpg R9A08G046_MIPI_DSI_ARESET_N>;
reset-names = "lvdrst", "prst", "rst", "arst";
power-domains = <&cpg>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
lvds0_in: endpoint {
remote-endpoint = <&du_out_lvds0>;
};
};
port@1 {
reg = <1>;
lvds0_out: endpoint {
remote-endpoint = <&panel_in>;
};
};
};
};
...

View File

@@ -19,6 +19,7 @@ properties:
- anbernic,rg-ds-display-bottom
- anbernic,rg-ds-display-top
- chongzhou,cz101b4001
- dcltek,dt300250
- kingdisplay,kd101ne3-40ti
- melfas,lmfbx101117480
- radxa,display-10hd-ad001

View File

@@ -37,6 +37,8 @@ properties:
- ampire,am-480272h3tmqw-t01h
# Ampire AM-800480L1TMQW-T00H 5" WVGA TFT LCD panel
- ampire,am-800480l1tmqw-t00h
# Ampire AM-800480N3TZQW-00H 5" WVGA TFT LCD panel
- ampire,am-800480n3tzqw-00h
# Ampire AM-800480R3TMQW-A1H 7.0" WVGA TFT LCD panel
- ampire,am800480r3tmqwa1h
# Ampire AM-800600P5TMQW-TB8H 8.0" SVGA TFT LCD panel

View File

@@ -22,6 +22,8 @@ properties:
enum:
# Anberic RG353V-V2 5.0" 640x480 TFT LCD panel
- anbernic,rg353v-panel-v2
# AYANEO Pocket DS lower 5.0" 1024x768 IPS LCD panel
- ayaneo,pocket-ds-lower-panel
# GameForce Chi 3.5" 640x480 TFT LCD panel
- gameforce,chi-panel
# Powkiddy RGB10MAX3 5.0" 720x1280 TFT LCD panel

View File

@@ -20,6 +20,7 @@ properties:
- enum:
- renesas,r9a07g043u-du # RZ/G2UL
- renesas,r9a07g044-du # RZ/G2{L,LC}
- renesas,r9a08g046-du # RZ/G3L
- renesas,r9a09g057-du # RZ/V2H(P)
- renesas,r9a09g077-du # RZ/T2H
- items:
@@ -65,7 +66,7 @@ properties:
model-dependent. Each port shall have a single endpoint.
patternProperties:
"^port@[0-1]$":
"^port@[0-2]$":
$ref: /schemas/graph.yaml#/properties/port
unevaluatedProperties: false
@@ -108,6 +109,7 @@ allOf:
port@0:
description: DPI
port@1: false
port@2: false
required:
- port@0
@@ -124,10 +126,31 @@ allOf:
description: DSI
port@1:
description: DPI
port@2: false
required:
- port@0
- port@1
- if:
properties:
compatible:
contains:
const: renesas,r9a08g046-du
then:
properties:
ports:
properties:
port@0:
description: DSI
port@1:
description: DPI
port@2:
description: LVDS
required:
- port@0
- port@1
- port@2
- if:
properties:
compatible:
@@ -140,6 +163,7 @@ allOf:
port@0:
description: DSI
port@1: false
port@2: false
required:
- port@0

View File

@@ -409,6 +409,8 @@ patternProperties:
description: DataImage, Inc.
"^davicom,.*":
description: DAVICOM Semiconductor, Inc.
"^dcltek,.*":
description: DCL Technologies Inc.
"^deepcomputing,.*":
description: DeepComputing (HK) Limited
"^dell,.*":
@@ -1253,6 +1255,8 @@ patternProperties:
description: OpenWrt
"^option,.*":
description: Option NV
"^optologic,.*":
description: Opto Logic S.A.
"^oranth,.*":
description: Shenzhen Oranth Technology Co., Ltd.
"^ORCL,.*":

View File

@@ -20,9 +20,9 @@ static int list_limit = 1024;
module_param(list_limit, int, 0644);
MODULE_PARM_DESC(list_limit, "udmabuf_create_list->count limit. Default is 1024.");
static int size_limit_mb = 64;
static int size_limit_mb = INT_MAX;
module_param(size_limit_mb, int, 0644);
MODULE_PARM_DESC(size_limit_mb, "Max size of a dmabuf, in megabytes. Default is 64.");
MODULE_PARM_DESC(size_limit_mb, "Max size of a dmabuf, in megabytes. Default is INT_MAX.");
struct udmabuf {
pgoff_t pagecount;

View File

@@ -7,7 +7,8 @@ config GPU_BUDDY
config GPU_BUDDY_KUNIT_TEST
tristate "KUnit tests for GPU buddy allocator" if !KUNIT_ALL_TESTS
depends on GPU_BUDDY && KUNIT
depends on KUNIT
select GPU_BUDDY
default KUNIT_ALL_TESTS
help
KUnit tests for the GPU buddy allocator.

View File

@@ -630,6 +630,59 @@ void gpu_buddy_free_block(struct gpu_buddy *mm,
}
EXPORT_SYMBOL(gpu_buddy_free_block);
/**
* gpu_buddy_allocated_addr_to_block - given relative address find the allocated block
*
* @mm: GPU buddy manager
* @addr: Relative address
*
* Returns:
* gpu_buddy_block on success, NULL or error code on failure
*/
struct gpu_buddy_block *gpu_buddy_allocated_addr_to_block(struct gpu_buddy *mm, u64 addr)
{
struct gpu_buddy_block *block;
LIST_HEAD(dfs);
u64 end;
int i;
gpu_buddy_driver_lock_held(mm);
end = addr + mm->chunk_size - 1;
for (i = 0; i < mm->n_roots; ++i)
list_add_tail(&mm->roots[i]->tmp_link, &dfs);
do {
u64 block_start;
u64 block_end;
block = list_first_entry_or_null(&dfs,
struct gpu_buddy_block,
tmp_link);
if (!block)
break;
list_del(&block->tmp_link);
block_start = gpu_buddy_block_offset(block);
block_end = block_start + gpu_buddy_block_size(mm, block) - 1;
if (!overlaps(addr, end, block_start, block_end))
continue;
if (gpu_buddy_block_is_allocated(block))
return block;
else if (gpu_buddy_block_is_free(block))
return NULL;
list_add(&block->right->tmp_link, &dfs);
list_add(&block->left->tmp_link, &dfs);
} while (1);
return ERR_PTR(-ENXIO);
}
EXPORT_SYMBOL(gpu_buddy_allocated_addr_to_block);
static void __gpu_buddy_free_list(struct gpu_buddy *mm,
struct list_head *objects,
bool mark_clear,

View File

@@ -1526,7 +1526,7 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo,
dma_resv_for_each_fence(&resv_cursor, bo->base.resv,
DMA_RESV_USAGE_BOOKKEEP, f) {
if (amdkfd_fence_check_mm(f, current->mm) &&
!(place->flags & TTM_PL_FLAG_CONTIGUOUS))
!(place && (place->flags & TTM_PL_FLAG_CONTIGUOUS)))
return false;
}

View File

@@ -23,6 +23,8 @@
*/
#include <linux/dma-mapping.h>
#include <linux/cgroup_dmem.h>
#include <linux/pm_runtime.h>
#include <drm/ttm/ttm_range_manager.h>
#include <drm/drm_drv.h>
#include <drm/drm_buddy.h>
@@ -905,6 +907,38 @@ static const struct ttm_resource_manager_func amdgpu_vram_mgr_func = {
.debug = amdgpu_vram_mgr_debug
};
static const struct dmem_cgroup_ops amdgpu_vram_mgr_dmem_ops;
static int amdgpu_vram_mgr_dmem_reclaim(struct dmem_cgroup_pool_state *pool,
u64 target_bytes, void *priv)
{
struct ttm_resource_manager *man = priv;
struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
int ret, idx;
if (!drm_dev_enter(adev_to_drm(adev), &idx))
return -ENODEV;
ret = pm_runtime_get_sync(adev_to_drm(adev)->dev);
if (ret < 0) {
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
goto out;
}
ret = ttm_resource_manager_dmem_reclaim(pool, target_bytes, priv);
pm_runtime_mark_last_busy(adev_to_drm(adev)->dev);
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
out:
drm_dev_exit(idx);
return ret;
}
static const struct dmem_cgroup_ops amdgpu_vram_mgr_dmem_ops = {
.reclaim = amdgpu_vram_mgr_dmem_reclaim,
};
/**
* amdgpu_vram_mgr_init - init VRAM manager and DRM MM
*
@@ -916,11 +950,9 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev)
{
struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr;
struct ttm_resource_manager *man = &mgr->manager;
struct dmem_cgroup_region *cg;
int err;
man->cg = drmm_cgroup_register_region(adev_to_drm(adev), "vram", adev->gmc.real_vram_size);
if (IS_ERR(man->cg))
return PTR_ERR(man->cg);
ttm_resource_manager_init(man, &adev->mman.bdev,
adev->gmc.real_vram_size);
@@ -935,6 +967,20 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev)
if (err)
return err;
cg = dmem_cgroup_register_region(&(struct dmem_cgroup_init){
.size = adev->gmc.real_vram_size,
.ops = &amdgpu_vram_mgr_dmem_ops,
.reclaim_priv = man,
},
"drm/%s/vram", adev_to_drm(adev)->unique);
if (IS_ERR(cg)) {
gpu_buddy_fini(&mgr->mm);
return PTR_ERR(cg);
}
mgr->cg_region = cg;
ttm_resource_manager_set_dmem_region(man, cg);
ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, &mgr->manager);
ttm_resource_manager_set_used(man, true);
return 0;
@@ -958,6 +1004,19 @@ void amdgpu_vram_mgr_fini(struct amdgpu_device *adev)
ttm_resource_manager_set_used(man, false);
ret = ttm_resource_manager_evict_all(&adev->mman.bdev, man);
/*
* Unregister the dmem cgroup region regardless of the evict_all()
* result and before any further teardown. This drains in-flight
* reclaim callbacks and blocks new ones, so no reclaim can reference
* the manager once we start freeing it. It must run after evict_all()
* so that ttm_resource_free() can still uncharge via man->cg during
* eviction. Clear man->cg afterwards.
*/
dmem_cgroup_unregister_region(mgr->cg_region);
mgr->cg_region = NULL;
ttm_resource_manager_set_dmem_region(man, NULL);
if (ret)
return;

View File

@@ -26,6 +26,8 @@
#include <linux/gpu_buddy.h>
struct dmem_cgroup_region;
struct amdgpu_vram_mgr {
struct ttm_resource_manager manager;
struct gpu_buddy mm;
@@ -36,6 +38,7 @@ struct amdgpu_vram_mgr {
atomic64_t vis_usage;
u64 default_page_size;
struct list_head allocated_vres_list;
struct dmem_cgroup_region *cg_region;
};
struct amdgpu_vres_task {

View File

@@ -1471,11 +1471,11 @@ static const struct adv7511_chip_info adv7535_chip_info = {
};
static const struct i2c_device_id adv7511_i2c_ids[] = {
{ "adv7511", (kernel_ulong_t)&adv7511_chip_info },
{ "adv7511w", (kernel_ulong_t)&adv7511_chip_info },
{ "adv7513", (kernel_ulong_t)&adv7511_chip_info },
{ "adv7533", (kernel_ulong_t)&adv7533_chip_info },
{ "adv7535", (kernel_ulong_t)&adv7535_chip_info },
{ .name = "adv7511", .driver_data = (kernel_ulong_t)&adv7511_chip_info },
{ .name = "adv7511w", .driver_data = (kernel_ulong_t)&adv7511_chip_info },
{ .name = "adv7513", .driver_data = (kernel_ulong_t)&adv7511_chip_info },
{ .name = "adv7533", .driver_data = (kernel_ulong_t)&adv7533_chip_info },
{ .name = "adv7535", .driver_data = (kernel_ulong_t)&adv7535_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, adv7511_i2c_ids);

View File

@@ -783,7 +783,7 @@ static void anx6345_i2c_remove(struct i2c_client *client)
}
static const struct i2c_device_id anx6345_id[] = {
{ "anx6345" },
{ .name = "anx6345" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, anx6345_id);

View File

@@ -2993,8 +2993,8 @@ static void anx7625_i2c_remove(struct i2c_client *client)
}
static const struct i2c_device_id anx7625_id[] = {
{ "anx7625" },
{}
{ .name = "anx7625" },
{ }
};
MODULE_DEVICE_TABLE(i2c, anx7625_id);

View File

@@ -784,8 +784,8 @@ static struct mipi_dsi_driver chipone_dsi_driver = {
};
static const struct i2c_device_id chipone_i2c_id[] = {
{ "chipone,icn6211" },
{},
{ .name = "chipone,icn6211" },
{ }
};
MODULE_DEVICE_TABLE(i2c, chipone_i2c_id);

View File

@@ -601,7 +601,7 @@ static const struct of_device_id ch7033_dt_ids[] = {
MODULE_DEVICE_TABLE(of, ch7033_dt_ids);
static const struct i2c_device_id ch7033_ids[] = {
{ "ch7033" },
{ .name = "ch7033" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ch7033_ids);

View File

@@ -107,4 +107,15 @@ config DRM_IMX93_MIPI_DSI
Choose this to enable MIPI DSI controller found in Freescale i.MX93
processor.
config DRM_IMX93_PARALLEL_DISP_FMT_CONVERTER
tristate "NXP i.MX91/i.MX93 parallel display format converter"
depends on OF
select DRM_KMS_HELPER
help
On i.MX93 and i.MX91 SoCs the parallel display format output is
controlled via the MEDIAMIX BLK-CTRL DISPLAY_MUX.
Say 'Y' or 'M' if you use the parallel display output path on a
i.MX93 or i.MX91 SoC.
endif # ARCH_MXC || COMPILE_TEST

View File

@@ -10,3 +10,4 @@ obj-$(CONFIG_DRM_IMX8QXP_PIXEL_COMBINER) += imx8qxp-pixel-combiner.o
obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK) += imx8qxp-pixel-link.o
obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK_TO_DPI) += imx8qxp-pxl2dpi.o
obj-$(CONFIG_DRM_IMX93_MIPI_DSI) += imx93-mipi-dsi.o
obj-$(CONFIG_DRM_IMX93_PARALLEL_DISP_FMT_CONVERTER) += imx93-pdfc.o

View File

@@ -0,0 +1,222 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2022-2025 NXP
*/
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/media-bus-format.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_bridge.h>
#define IMX93_DISPLAY_MUX_REG 0x60
#define PARALLEL_DISP_FORMAT GENMASK(10, 8)
#define FORMAT_RGB888_TO_RGB888 FIELD_PREP(PARALLEL_DISP_FORMAT, 0)
#define FORMAT_RGB888_TO_RGB666 FIELD_PREP(PARALLEL_DISP_FORMAT, 1)
#define FORMAT_RGB565_TO_RGB565 FIELD_PREP(PARALLEL_DISP_FORMAT, 2)
struct imx93_pdfc {
struct drm_bridge bridge;
struct device *dev;
struct regmap *regmap;
u32 phy_bus_width;
};
static struct imx93_pdfc *bridge_to_imx93_pdfc(struct drm_bridge *bridge)
{
return container_of(bridge, struct imx93_pdfc, bridge);
}
static int
imx93_pdfc_bridge_attach(struct drm_bridge *bridge, struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
return drm_bridge_attach(bridge->encoder, bridge->next_bridge, bridge, flags);
}
static void imx93_pdfc_bridge_atomic_enable(struct drm_bridge *bridge,
struct drm_atomic_commit *state)
{
struct imx93_pdfc *pdfc = bridge_to_imx93_pdfc(bridge);
const struct drm_bridge_state *bridge_state;
unsigned int mask = PARALLEL_DISP_FORMAT;
unsigned int val;
bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
switch (bridge_state->output_bus_cfg.format) {
case MEDIA_BUS_FMT_RGB888_1X24:
case MEDIA_BUS_FMT_FIXED:
val = FORMAT_RGB888_TO_RGB888;
if (pdfc->phy_bus_width == 18) {
/*
* Can be valid if physical bus limitation exists,
* therefore use dev_dbg().
*/
dev_dbg(pdfc->dev, "Truncate two LSBs from each color\n");
val = FORMAT_RGB888_TO_RGB666;
}
break;
case MEDIA_BUS_FMT_RGB666_1X18:
val = FORMAT_RGB888_TO_RGB666;
break;
case MEDIA_BUS_FMT_RGB565_1X16:
val = FORMAT_RGB565_TO_RGB565;
break;
}
regmap_update_bits(pdfc->regmap, IMX93_DISPLAY_MUX_REG, mask, val);
}
/* TODO: Add YUV formats */
static const u32 imx93_pdfc_bus_output_fmts[] = {
MEDIA_BUS_FMT_FIXED,
MEDIA_BUS_FMT_RGB888_1X24,
MEDIA_BUS_FMT_RGB666_1X18,
MEDIA_BUS_FMT_RGB565_1X16,
};
static bool imx93_pdfc_bus_output_fmt_supported(u32 fmt)
{
int i;
for (i = 0; i < ARRAY_SIZE(imx93_pdfc_bus_output_fmts); i++) {
if (imx93_pdfc_bus_output_fmts[i] == fmt)
return true;
}
return false;
}
static u32 *
imx93_pdfc_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
struct drm_bridge_state *bridge_state,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state,
u32 output_fmt,
unsigned int *num_input_fmts)
{
u32 *input_fmts;
*num_input_fmts = 0;
if (!imx93_pdfc_bus_output_fmt_supported(output_fmt))
return NULL;
input_fmts = kmalloc_obj(*input_fmts);
if (!input_fmts)
return NULL;
*num_input_fmts = 1;
switch (output_fmt) {
case MEDIA_BUS_FMT_RGB888_1X24:
case MEDIA_BUS_FMT_RGB565_1X16:
input_fmts[0] = output_fmt;
break;
case MEDIA_BUS_FMT_RGB666_1X18:
case MEDIA_BUS_FMT_FIXED:
input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;
break;
}
return input_fmts;
}
static int imx93_pdfc_bridge_atomic_check(struct drm_bridge *bridge,
struct drm_bridge_state *bridge_state,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
{
struct imx93_pdfc *pdfc = bridge_to_imx93_pdfc(bridge);
u32 format = bridge_state->output_bus_cfg.format;
if (imx93_pdfc_bus_output_fmt_supported(format))
return 0;
dev_warn(pdfc->dev, "Unsupported output bus format: 0x%x\n", format);
return -EINVAL;
}
static const struct drm_bridge_funcs funcs = {
.attach = imx93_pdfc_bridge_attach,
.atomic_enable = imx93_pdfc_bridge_atomic_enable,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_get_input_bus_fmts = imx93_pdfc_bridge_atomic_get_input_bus_fmts,
.atomic_check = imx93_pdfc_bridge_atomic_check,
.atomic_create_state = drm_atomic_helper_bridge_create_state,
};
static int imx93_pdfc_bridge_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct drm_bridge *next_bridge;
struct imx93_pdfc *pdfc;
struct device_node *ep;
int err;
pdfc = devm_drm_bridge_alloc(dev, struct imx93_pdfc, bridge, &funcs);
if (IS_ERR(pdfc))
return PTR_ERR(pdfc);
pdfc->regmap = syscon_node_to_regmap(dev->of_node->parent);
if (IS_ERR(pdfc->regmap))
return dev_err_probe(dev, PTR_ERR(pdfc->regmap),
"failed to get regmap\n");
/* No limits per default */
pdfc->phy_bus_width = 24;
/* Get output ep (port1/endpoint) */
ep = of_graph_get_endpoint_by_regs(dev->of_node, 1, -1);
if (ep) {
err = of_property_read_u32(ep, "bus-width", &pdfc->phy_bus_width);
of_node_put(ep);
/* bus-width is optional but it must have valid data if present */
if (err && err != -EINVAL)
return dev_err_probe(dev, err,
"failed to query bus-width\n");
}
next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
if (IS_ERR(next_bridge))
return dev_err_probe(dev, PTR_ERR(next_bridge),
"failed to get next bridge\n");
pdfc->dev = dev;
pdfc->bridge.of_node = dev->of_node;
pdfc->bridge.type = DRM_MODE_CONNECTOR_DPI;
pdfc->bridge.next_bridge = drm_bridge_get(next_bridge);
return devm_drm_bridge_add(dev, &pdfc->bridge);
}
static const struct of_device_id imx93_pdfc_dt_ids[] = {
{ .compatible = "nxp,imx91-pdfc", },
{ .compatible = "nxp,imx93-pdfc", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx93_pdfc_dt_ids);
static struct platform_driver imx93_pdfc_bridge_driver = {
.probe = imx93_pdfc_bridge_probe,
.driver = {
.of_match_table = imx93_pdfc_dt_ids,
.name = "imx93_pdfc",
},
};
module_platform_driver(imx93_pdfc_bridge_driver);
MODULE_DESCRIPTION("NXP i.MX93 parallel display format configuration driver");
MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>");
MODULE_LICENSE("GPL");

View File

@@ -910,7 +910,7 @@ static const struct of_device_id it6263_of_match[] = {
MODULE_DEVICE_TABLE(of, it6263_of_match);
static const struct i2c_device_id it6263_i2c_ids[] = {
{ "it6263" },
{ .name = "it6263" },
{ }
};
MODULE_DEVICE_TABLE(i2c, it6263_i2c_ids);

View File

@@ -3652,7 +3652,7 @@ static void it6505_i2c_remove(struct i2c_client *client)
}
static const struct i2c_device_id it6505_id[] = {
{ "it6505" },
{ .name = "it6505" },
{ }
};

View File

@@ -572,7 +572,7 @@ static void lt8713sx_remove(struct i2c_client *client)
}
static struct i2c_device_id lt8713sx_id[] = {
{ "lontium,lt8713sx", 0 },
{ .name = "lontium,lt8713sx" },
{ /* sentinel */ }
};

View File

@@ -677,7 +677,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(lt8912_bridge_pm_ops, lt8912_bridge_suspend, lt8
static int lt8912_get_regulators(struct lt8912 *lt)
{
unsigned int i;
const char * const supply_names[] = {
static const char * const supply_names[] = {
"vdd", "vccmipirx", "vccsysclk", "vcclvdstx",
"vcchdmitx", "vcclvdspll", "vcchdmipll"
};
@@ -820,8 +820,8 @@ static const struct of_device_id lt8912_dt_match[] = {
MODULE_DEVICE_TABLE(of, lt8912_dt_match);
static const struct i2c_device_id lt8912_id[] = {
{ "lt8912" },
{}
{ .name = "lt8912" },
{ }
};
MODULE_DEVICE_TABLE(i2c, lt8912_id);

View File

@@ -773,8 +773,8 @@ static void lt9211_remove(struct i2c_client *client)
}
static const struct i2c_device_id lt9211_id[] = {
{ "lontium,lt9211" },
{},
{ .name = "lontium,lt9211" },
{ }
};
MODULE_DEVICE_TABLE(i2c, lt9211_id);

View File

@@ -1229,8 +1229,8 @@ static void lt9611_remove(struct i2c_client *client)
}
static const struct i2c_device_id lt9611_id[] = {
{ "lontium,lt9611" },
{}
{ .name = "lontium,lt9611" },
{ }
};
MODULE_DEVICE_TABLE(i2c, lt9611_id);

View File

@@ -899,7 +899,7 @@ static void lt9611uxc_remove(struct i2c_client *client)
}
static const struct i2c_device_id lt9611uxc_id[] = {
{ "lontium,lt9611uxc" },
{ .name = "lontium,lt9611uxc" },
{ /* sentinel */ }
};

View File

@@ -317,8 +317,8 @@ static void stdp4028_ge_b850v3_fw_remove(struct i2c_client *stdp4028_i2c)
}
static const struct i2c_device_id stdp4028_ge_b850v3_fw_i2c_table[] = {
{ "stdp4028_ge_fw" },
{}
{ .name = "stdp4028_ge_fw" },
{ }
};
MODULE_DEVICE_TABLE(i2c, stdp4028_ge_b850v3_fw_i2c_table);
@@ -364,8 +364,8 @@ static void stdp2690_ge_b850v3_fw_remove(struct i2c_client *stdp2690_i2c)
}
static const struct i2c_device_id stdp2690_ge_b850v3_fw_i2c_table[] = {
{ "stdp2690_ge_fw" },
{}
{ .name = "stdp2690_ge_fw" },
{ }
};
MODULE_DEVICE_TABLE(i2c, stdp2690_ge_b850v3_fw_i2c_table);

View File

@@ -323,8 +323,8 @@ static void ptn3460_remove(struct i2c_client *client)
}
static const struct i2c_device_id ptn3460_i2c_table[] = {
{ "ptn3460" },
{}
{ .name = "ptn3460" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ptn3460_i2c_table);

View File

@@ -534,10 +534,10 @@ static void ps8622_remove(struct i2c_client *client)
}
static const struct i2c_device_id ps8622_i2c_table[] = {
/* Device type, max_lane_count */
{"ps8622", 1},
{"ps8625", 2},
{},
/* Device type, driver_data holds the maximal lane_count */
{ .name = "ps8622", .driver_data = 1 },
{ .name = "ps8625", .driver_data = 2 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ps8622_i2c_table);

View File

@@ -1235,7 +1235,7 @@ static const struct of_device_id sii902x_dt_ids[] = {
MODULE_DEVICE_TABLE(of, sii902x_dt_ids);
static const struct i2c_device_id sii902x_i2c_ids[] = {
{ "sii9022" },
{ .name = "sii9022" },
{ }
};
MODULE_DEVICE_TABLE(i2c, sii902x_i2c_ids);

View File

@@ -944,7 +944,7 @@ static const struct of_device_id sii9234_dt_match[] = {
MODULE_DEVICE_TABLE(of, sii9234_dt_match);
static const struct i2c_device_id sii9234_id[] = {
{ "SII9234" },
{ .name = "SII9234" },
{ }
};
MODULE_DEVICE_TABLE(i2c, sii9234_id);

View File

@@ -2374,7 +2374,7 @@ static const struct of_device_id sii8620_dt_match[] = {
MODULE_DEVICE_TABLE(of, sii8620_dt_match);
static const struct i2c_device_id sii8620_id[] = {
{ "sii8620" },
{ .name = "sii8620" },
{ }
};

View File

@@ -1949,7 +1949,6 @@ static const struct regmap_config dw_dp_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.fast_io = true,
.max_register = DW_DP_MAX_REGISTER,
.rd_table = &dw_dp_readable_table,
};

View File

@@ -3389,7 +3389,8 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
break;
default:
dev_err(dev, "reg-io-width must be 1 or 4\n");
return ERR_PTR(-EINVAL);
ret = -EINVAL;
goto err_res;
}
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);

View File

@@ -907,7 +907,6 @@ static const struct regmap_config dw_mipi_dsi2_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.fast_io = true,
};
static struct dw_mipi_dsi2 *

View File

@@ -292,25 +292,17 @@ static int tc358762_probe(struct mipi_dsi_device *dsi)
ctx->bridge.of_node = dev->of_node;
ctx->bridge.pre_enable_prev_first = true;
drm_bridge_add(&ctx->bridge);
ret = devm_drm_bridge_add(dev, &ctx->bridge);
if (ret < 0)
return ret;
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
drm_bridge_remove(&ctx->bridge);
ret = devm_mipi_dsi_attach(dev, dsi);
if (ret < 0)
dev_err(dev, "failed to attach dsi\n");
}
return ret;
}
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);
}
static const struct of_device_id tc358762_of_match[] = {
{ .compatible = "toshiba,tc358762" },
{ }
@@ -319,7 +311,6 @@ MODULE_DEVICE_TABLE(of, tc358762_of_match);
static struct mipi_dsi_driver tc358762_driver = {
.probe = tc358762_probe,
.remove = tc358762_remove,
.driver = {
.name = "tc358762",
.of_match_table = tc358762_of_match,

View File

@@ -376,25 +376,17 @@ static int tc358764_probe(struct mipi_dsi_device *dsi)
ctx->bridge.of_node = dev->of_node;
ctx->bridge.pre_enable_prev_first = true;
drm_bridge_add(&ctx->bridge);
ret = devm_drm_bridge_add(dev, &ctx->bridge);
if (ret < 0)
return ret;
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
drm_bridge_remove(&ctx->bridge);
ret = devm_mipi_dsi_attach(dev, dsi);
if (ret < 0)
dev_err(dev, "failed to attach dsi\n");
}
return ret;
}
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);
}
static const struct of_device_id tc358764_of_match[] = {
{ .compatible = "toshiba,tc358764" },
{ }
@@ -403,7 +395,6 @@ MODULE_DEVICE_TABLE(of, tc358764_of_match);
static struct mipi_dsi_driver tc358764_driver = {
.probe = tc358764_probe,
.remove = tc358764_remove,
.driver = {
.name = "tc358764",
.of_match_table = tc358764_of_match,

View File

@@ -2613,7 +2613,7 @@ static void tc_remove(struct i2c_client *client)
}
static const struct i2c_device_id tc358767_i2c_ids[] = {
{ "tc358767" },
{ .name = "tc358767" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tc358767_i2c_ids);

View File

@@ -1362,8 +1362,8 @@ static const struct regmap_config tc358768_regmap_config = {
};
static const struct i2c_device_id tc358768_i2c_ids[] = {
{ "tc358768" },
{ "tc358778" },
{ .name = "tc358768" },
{ .name = "tc358778" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tc358768_i2c_ids);

View File

@@ -727,8 +727,8 @@ static void tc_remove(struct i2c_client *client)
}
static const struct i2c_device_id tc358775_i2c_ids[] = {
{ "tc358765", TC358765, },
{ "tc358775", TC358775, },
{ .name = "tc358765", .driver_data = TC358765 },
{ .name = "tc358775", .driver_data = TC358775 },
{ }
};
MODULE_DEVICE_TABLE(i2c, tc358775_i2c_ids);

View File

@@ -2064,7 +2064,7 @@ MODULE_DEVICE_TABLE(of, tda998x_dt_ids);
#endif
static const struct i2c_device_id tda998x_ids[] = {
{ "tda998x" },
{ .name = "tda998x" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tda998x_ids);

View File

@@ -389,7 +389,7 @@ static void dlpc3433_remove(struct i2c_client *client)
}
static const struct i2c_device_id dlpc3433_id[] = {
{ "ti,dlpc3433" },
{ .name = "ti,dlpc3433" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, dlpc3433_id);

View File

@@ -1072,9 +1072,9 @@ static void sn65dsi83_remove(struct i2c_client *client)
}
static const struct i2c_device_id sn65dsi83_id[] = {
{ "ti,sn65dsi83", MODEL_SN65DSI83 },
{ "ti,sn65dsi84", MODEL_SN65DSI84 },
{},
{ .name = "ti,sn65dsi83", .driver_data = MODEL_SN65DSI83 },
{ .name = "ti,sn65dsi84", .driver_data = MODEL_SN65DSI84 },
{ }
};
MODULE_DEVICE_TABLE(i2c, sn65dsi83_id);

View File

@@ -2080,7 +2080,7 @@ static int ti_sn65dsi86_probe(struct i2c_client *client)
dev_name(pdata->dev), pdata);
if (ret)
return dev_err_probe(dev, ret, "failed to request interrupt\n");
return ret;
}
/*
@@ -2116,8 +2116,8 @@ static int ti_sn65dsi86_probe(struct i2c_client *client)
}
static const struct i2c_device_id ti_sn65dsi86_id[] = {
{ "ti,sn65dsi86" },
{}
{ .name = "ti,sn65dsi86" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ti_sn65dsi86_id);

View File

@@ -437,7 +437,7 @@ static void tfp410_i2c_remove(struct i2c_client *client)
}
static const struct i2c_device_id tfp410_i2c_ids[] = {
{ "tfp410" },
{ .name = "tfp410" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tfp410_i2c_ids);

View File

@@ -960,17 +960,19 @@ static void drmm_cg_unregister_region(struct drm_device *dev, void *arg)
* drmm_cgroup_register_region - Register a region of a DRM device to cgroups
* @dev: device for region
* @region_name: Region name for registering
* @size: Size of region in bytes
* @init: Initialization parameters for the region.
*
* This decreases the ref-count of @dev by one. The device is destroyed if the
* ref-count drops to zero.
*/
struct dmem_cgroup_region *drmm_cgroup_register_region(struct drm_device *dev, const char *region_name, u64 size)
struct dmem_cgroup_region *
drmm_cgroup_register_region(struct drm_device *dev, const char *region_name,
const struct dmem_cgroup_init *init)
{
struct dmem_cgroup_region *region;
int ret;
region = dmem_cgroup_register_region(size, "drm/%s/%s", dev->unique, region_name);
region = dmem_cgroup_register_region(init, "drm/%s/%s", dev->unique, region_name);
if (IS_ERR_OR_NULL(region))
return region;

View File

@@ -255,7 +255,7 @@ pvr_kccb_used_slot_count_locked(struct pvr_device *pvr_dev)
* pvr_kccb_send_cmd_reserved_powered() - Send command to the KCCB, with the PM ref
* held and a slot pre-reserved
* @pvr_dev: Device pointer.
* @cmd: Command to sent.
* @cmd: Command to send.
* @kccb_slot: Address to store the KCCB slot for this command. May be %NULL.
*/
void
@@ -361,7 +361,7 @@ static int pvr_kccb_reserve_slot_sync(struct pvr_device *pvr_dev)
/**
* pvr_kccb_send_cmd_powered() - Send command to the KCCB, with a PM ref held
* @pvr_dev: Device pointer.
* @cmd: Command to sent.
* @cmd: Command to send.
* @kccb_slot: Address to store the KCCB slot for this command. May be %NULL.
*
* Returns:
@@ -385,7 +385,7 @@ pvr_kccb_send_cmd_powered(struct pvr_device *pvr_dev, struct rogue_fwif_kccb_cmd
/**
* pvr_kccb_send_cmd() - Send command to the KCCB
* @pvr_dev: Device pointer.
* @cmd: Command to sent.
* @cmd: Command to send.
* @kccb_slot: Address to store the KCCB slot for this command. May be %NULL.
*
* Returns:

View File

@@ -0,0 +1,36 @@
/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
/* Copyright (c) 2026 Imagination Technologies Ltd. */
#ifndef PVR_CHECK_H
#define PVR_CHECK_H
#include <linux/build_bug.h>
#include <linux/overflow.h>
#include <linux/stddef.h>
#define OFFSET_CHECK(type, member, offset) \
static_assert(offsetof(type, member) == (offset), \
"offsetof(" #type ", " #member ") incorrect")
#define SIZE_CHECK(type, size) \
static_assert(sizeof(type) == (size), #type " is incorrect size")
#define ALIGN_CHECK(type, align) \
static_assert(__alignof__(type) <= (align), #type " has incorrect alignment")
/*
* Where the last member of a struct is a flexible array member, using
* SIZE_CHECK() is pointless. If the structure is not already padded to
* alignment without the flexible array member, sizeof() will not match the
* offset of the flexible array member and the "correct" sizeof() value is
* completely meaningless.
*
* In those instances, use FLEX_ARRAY_CHECK() instead to assert that the final
* field is a flexible array member and that it behaves as expected.
*/
#define FLEX_ARRAY_CHECK(type, member) \
static_assert(flex_array_size((type *)NULL, member, 1) == \
sizeof_field(type, member[0]), \
#type "->" #member " is incorrect size")
#endif /* PVR_CHECK_H */

View File

@@ -22,12 +22,12 @@ struct pvr_device_features {
bool has_coreid_per_os;
bool has_dynamic_dust_power;
bool has_ecc_rams;
bool has_fb_cdc_v4;
bool has_fbc_max_default_descriptors;
bool has_fbc_max_large_descriptors;
bool has_fbcdc;
bool has_fbcdc_algorithm;
bool has_fbcdc_architecture;
bool has_fbc_max_default_descriptors;
bool has_fbc_max_large_descriptors;
bool has_fb_cdc_v4;
bool has_gpu_multicore_support;
bool has_gpu_virtualisation;
bool has_gs_rta_support;

View File

@@ -84,8 +84,10 @@ struct pvr_gem_object {
/**
* @base: The underlying &struct drm_gem_shmem_object.
*
* Do not access this member directly, instead call
* shem_gem_from_pvr_gem().
* .. note::
*
* This member should not be accessed directly, but instead by
* calling shmem_gem_from_pvr_gem().
*/
struct drm_gem_shmem_object base;
@@ -97,12 +99,6 @@ struct pvr_gem_object {
* changed after creation.
*
* Must be a combination of DRM_PVR_BO_* and/or PVR_BO_* flags.
*
* .. note::
*
* This member is declared const to indicate that none of these
* options may change or be changed throughout the object's
* lifetime.
*/
u64 flags;

View File

@@ -17,6 +17,7 @@
#include "pvr_rogue_fwif_client.h"
#define MAX_DEADLINE_MS 30000
#define SCHED_TIMEOUT_PERIOD (2 * MAX_DEADLINE_MS)
#define CTX_COMPUTE_CCCB_SIZE_LOG2 15
#define CTX_FRAG_CCCB_SIZE_LOG2 15
@@ -1283,7 +1284,7 @@ struct pvr_queue *pvr_queue_create(struct pvr_context *ctx,
.submit_wq = pvr_dev->sched_wq,
.credit_limit = 64 * 1024,
.hang_limit = 1,
.timeout = msecs_to_jiffies(500),
.timeout = msecs_to_jiffies(SCHED_TIMEOUT_PERIOD),
.timeout_wq = pvr_dev->sched_wq,
.name = "pvr-queue",
.dev = pvr_dev->base.dev,

View File

@@ -4,31 +4,7 @@
#ifndef PVR_ROGUE_FWIF_CHECK_H
#define PVR_ROGUE_FWIF_CHECK_H
#include <linux/build_bug.h>
#include <linux/overflow.h>
#include <linux/stddef.h>
#define OFFSET_CHECK(type, member, offset) \
static_assert(offsetof(type, member) == (offset), \
"offsetof(" #type ", " #member ") incorrect")
#define SIZE_CHECK(type, size) \
static_assert(sizeof(type) == (size), #type " is incorrect size")
/*
* Where the last member of a struct is a flexible array member, using
* SIZE_CHECK() is pointless. If the structure is not already padded to
* alignment without the flexible array member, sizeof() will not match the
* offset of the flexible array member and the "correct" sizeof() value is
* completely meaningless.
*
* In those instances, use FLEX_ARRAY_CHECK() instead to assert that the final
* field is a flexible array member and that it behaves as expected.
*/
#define FLEX_ARRAY_CHECK(type, member) \
static_assert(flex_array_size((type *)NULL, member, 1) == \
sizeof_field(type, member[0]), \
#type "->" #member " is incorrect size")
#include "pvr_check.h"
OFFSET_CHECK(struct rogue_fwif_file_info_buf, path, 0);
OFFSET_CHECK(struct rogue_fwif_file_info_buf, info, 200);

View File

@@ -4,14 +4,7 @@
#ifndef PVR_ROGUE_FWIF_CLIENT_CHECK_H
#define PVR_ROGUE_FWIF_CLIENT_CHECK_H
#include <linux/build_bug.h>
#define OFFSET_CHECK(type, member, offset) \
static_assert(offsetof(type, member) == (offset), \
"offsetof(" #type ", " #member ") incorrect")
#define SIZE_CHECK(type, size) \
static_assert(sizeof(type) == (size), #type " is incorrect size")
#include "pvr_check.h"
OFFSET_CHECK(struct rogue_fwif_geom_regs, vdm_ctrl_stream_base, 0);
OFFSET_CHECK(struct rogue_fwif_geom_regs, tpu_border_colour_table, 8);

View File

@@ -4,14 +4,7 @@
#ifndef PVR_ROGUE_FWIF_SHARED_CHECK_H
#define PVR_ROGUE_FWIF_SHARED_CHECK_H
#include <linux/build_bug.h>
#define OFFSET_CHECK(type, member, offset) \
static_assert(offsetof(type, member) == (offset), \
"offsetof(" #type ", " #member ") incorrect")
#define SIZE_CHECK(type, size) \
static_assert(sizeof(type) == (size), #type " is incorrect size")
#include "pvr_check.h"
OFFSET_CHECK(struct rogue_fwif_dma_addr, dev_addr, 0);
OFFSET_CHECK(struct rogue_fwif_dma_addr, fw_addr, 8);

View File

@@ -33,12 +33,12 @@
/* 0 MiB to 4 MiB, size of 4 MiB : RESERVED */
/* 0x00_0040_0000 - 0x7F_FFC0_0000 **/
/* 4 MiB to 512 GiB, size of 512 GiB less 4 MiB : RESERVED **/
/* 4 MiB to 512 GiB, size of 512 GiB less 4 MiB : RESERVED */
/* 0x80_0000_0000 ************************************************************/
/* 0x80_0000_0000 - 0x9F_FFFF_FFFF **/
/* 512 GiB to 640 GiB, size of 128 GiB : GENERAL_HEAP **/
/* 512 GiB to 640 GiB, size of 128 GiB : GENERAL_HEAP */
#define ROGUE_GENERAL_HEAP_BASE 0x8000000000ull
#define ROGUE_GENERAL_HEAP_SIZE SZ_128G
@@ -62,7 +62,7 @@
#define ROGUE_PDSCODEDATA_HEAP_SIZE SZ_4G
/* 0xDB_0000_0000 - 0xDB_FFFF_FFFF */
/* 876 GiB to 880 GiB, size of 256 MiB (reserved 4GiB) : BRN **/
/* 876 GiB to 880 GiB, size of 256 MiB (reserved 4GiB) : BRN */
/*
* The BRN63142 quirk workaround requires Region Header memory to be at the top
* of a 16GiB aligned range. This is so when masked with 0x03FFFFFFFF the
@@ -82,7 +82,7 @@
/* 0xE1_0000_0000 - 0xE1_BFFF_FFFF */
/* 900 GiB to 903 GiB, size of 3 GiB : RESERVED */
/* 0xE1_C000_000 - 0xE1_FFFF_FFFF */
/* 0xE1_C000_0000 - 0xE1_FFFF_FFFF */
/* 903 GiB to 904 GiB, reserved 1 GiB, : FIRMWARE_HEAP */
#define ROGUE_FW_HEAP_BASE 0xE1C0000000ull
@@ -90,7 +90,7 @@
/* 904 GiB to 912 GiB, size of 8 GiB : FREE */
/* 0xE4_0000_0000 - 0xE7_FFFF_FFFF */
/* 912 GiB to 968 GiB, size of 16 GiB : TRANSFER_FRAG */
/* 912 GiB to 928 GiB, size of 16 GiB : TRANSFER_FRAG */
#define ROGUE_TRANSFER_FRAG_HEAP_BASE 0xE400000000ull
#define ROGUE_TRANSFER_FRAG_HEAP_SIZE SZ_16G

View File

@@ -4,55 +4,32 @@
#ifndef PVR_ROGUE_MIPS_CHECK_H
#define PVR_ROGUE_MIPS_CHECK_H
#include <linux/build_bug.h>
#include "pvr_check.h"
static_assert(offsetof(struct rogue_mips_tlb_entry, tlb_page_mask) == 0,
"offsetof(struct rogue_mips_tlb_entry, tlb_page_mask) incorrect");
static_assert(offsetof(struct rogue_mips_tlb_entry, tlb_hi) == 4,
"offsetof(struct rogue_mips_tlb_entry, tlb_hi) incorrect");
static_assert(offsetof(struct rogue_mips_tlb_entry, tlb_lo0) == 8,
"offsetof(struct rogue_mips_tlb_entry, tlb_lo0) incorrect");
static_assert(offsetof(struct rogue_mips_tlb_entry, tlb_lo1) == 12,
"offsetof(struct rogue_mips_tlb_entry, tlb_lo1) incorrect");
static_assert(sizeof(struct rogue_mips_tlb_entry) == 16,
"struct rogue_mips_tlb_entry is incorrect size");
OFFSET_CHECK(struct rogue_mips_tlb_entry, tlb_page_mask, 0);
OFFSET_CHECK(struct rogue_mips_tlb_entry, tlb_hi, 4);
OFFSET_CHECK(struct rogue_mips_tlb_entry, tlb_lo0, 8);
OFFSET_CHECK(struct rogue_mips_tlb_entry, tlb_lo1, 12);
SIZE_CHECK(struct rogue_mips_tlb_entry, 16);
static_assert(offsetof(struct rogue_mips_remap_entry, remap_addr_in) == 0,
"offsetof(struct rogue_mips_remap_entry, remap_addr_in) incorrect");
static_assert(offsetof(struct rogue_mips_remap_entry, remap_addr_out) == 4,
"offsetof(struct rogue_mips_remap_entry, remap_addr_out) incorrect");
static_assert(offsetof(struct rogue_mips_remap_entry, remap_region_size) == 8,
"offsetof(struct rogue_mips_remap_entry, remap_region_size) incorrect");
static_assert(sizeof(struct rogue_mips_remap_entry) == 12,
"struct rogue_mips_remap_entry is incorrect size");
OFFSET_CHECK(struct rogue_mips_remap_entry, remap_addr_in, 0);
OFFSET_CHECK(struct rogue_mips_remap_entry, remap_addr_out, 4);
OFFSET_CHECK(struct rogue_mips_remap_entry, remap_region_size, 8);
SIZE_CHECK(struct rogue_mips_remap_entry, 12);
static_assert(offsetof(struct rogue_mips_state, error_state) == 0,
"offsetof(struct rogue_mips_state, error_state) incorrect");
static_assert(offsetof(struct rogue_mips_state, error_epc) == 4,
"offsetof(struct rogue_mips_state, error_epc) incorrect");
static_assert(offsetof(struct rogue_mips_state, status_register) == 8,
"offsetof(struct rogue_mips_state, status_register) incorrect");
static_assert(offsetof(struct rogue_mips_state, cause_register) == 12,
"offsetof(struct rogue_mips_state, cause_register) incorrect");
static_assert(offsetof(struct rogue_mips_state, bad_register) == 16,
"offsetof(struct rogue_mips_state, bad_register) incorrect");
static_assert(offsetof(struct rogue_mips_state, epc) == 20,
"offsetof(struct rogue_mips_state, epc) incorrect");
static_assert(offsetof(struct rogue_mips_state, sp) == 24,
"offsetof(struct rogue_mips_state, sp) incorrect");
static_assert(offsetof(struct rogue_mips_state, debug) == 28,
"offsetof(struct rogue_mips_state, debug) incorrect");
static_assert(offsetof(struct rogue_mips_state, depc) == 32,
"offsetof(struct rogue_mips_state, depc) incorrect");
static_assert(offsetof(struct rogue_mips_state, bad_instr) == 36,
"offsetof(struct rogue_mips_state, bad_instr) incorrect");
static_assert(offsetof(struct rogue_mips_state, unmapped_address) == 40,
"offsetof(struct rogue_mips_state, unmapped_address) incorrect");
static_assert(offsetof(struct rogue_mips_state, tlb) == 44,
"offsetof(struct rogue_mips_state, tlb) incorrect");
static_assert(offsetof(struct rogue_mips_state, remap) == 300,
"offsetof(struct rogue_mips_state, remap) incorrect");
static_assert(sizeof(struct rogue_mips_state) == 684,
"struct rogue_mips_state is incorrect size");
OFFSET_CHECK(struct rogue_mips_state, error_state, 0);
OFFSET_CHECK(struct rogue_mips_state, error_epc, 4);
OFFSET_CHECK(struct rogue_mips_state, status_register, 8);
OFFSET_CHECK(struct rogue_mips_state, cause_register, 12);
OFFSET_CHECK(struct rogue_mips_state, bad_register, 16);
OFFSET_CHECK(struct rogue_mips_state, epc, 20);
OFFSET_CHECK(struct rogue_mips_state, sp, 24);
OFFSET_CHECK(struct rogue_mips_state, debug, 28);
OFFSET_CHECK(struct rogue_mips_state, depc, 32);
OFFSET_CHECK(struct rogue_mips_state, bad_instr, 36);
OFFSET_CHECK(struct rogue_mips_state, unmapped_address, 40);
OFFSET_CHECK(struct rogue_mips_state, tlb, 44);
OFFSET_CHECK(struct rogue_mips_state, remap, 300);
SIZE_CHECK(struct rogue_mips_state, 684);
#endif /* PVR_ROGUE_MIPS_CHECK_H */

View File

@@ -1,5 +1,7 @@
#ifndef __NV50_KMS_BASE_H__
#define __NV50_KMS_BASE_H__
#include <drm/drm_blend.h>
#include "wndw.h"
int base507c_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);
@@ -24,4 +26,8 @@ extern const struct nv50_wndw_func base907c;
int base917c_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);
int nv50_base_new(struct nouveau_drm *, int head, struct nv50_wndw **);
/* The only blend mode supported by base channels */
#define BASE_BLEND_MODES BIT(DRM_MODE_BLEND_PIXEL_NONE)
#endif

View File

@@ -297,6 +297,7 @@ base507c = {
.image_set = base507c_image_set,
.image_clr = base507c_image_clr,
.update = base507c_update,
.blend_modes = BASE_BLEND_MODES,
};
int

View File

@@ -93,6 +93,7 @@ base827c = {
.image_set = base827c_image_set,
.image_clr = base507c_image_clr,
.update = base507c_update,
.blend_modes = BASE_BLEND_MODES,
};
int

View File

@@ -205,6 +205,7 @@ base907c = {
.image_set = base907c_image_set,
.image_clr = base507c_image_clr,
.update = base507c_update,
.blend_modes = BASE_BLEND_MODES,
};
int

View File

@@ -29,6 +29,7 @@
#include <nvhw/class/cl507a.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_blend.h>
#include <drm/drm_fourcc.h>
bool
@@ -164,6 +165,8 @@ curs507a_wndw = {
.acquire = curs507a_acquire,
.release = curs507a_release,
.prepare = curs507a_prepare,
// TODO: Cursors also support premulti, but we haven't hooked it up anywhere yet.
.blend_modes = BIT(DRM_MODE_BLEND_COVERAGE),
};
int

View File

@@ -2768,6 +2768,7 @@ nv50_display_read_hw_state(struct nouveau_drm *drm)
{
struct drm_device *dev = drm->dev;
struct drm_encoder *encoder;
struct drm_plane *plane;
struct drm_modeset_acquire_ctx ctx;
struct nv50_disp *disp = nv50_disp(dev);
int ret;
@@ -2781,6 +2782,9 @@ nv50_display_read_hw_state(struct nouveau_drm *drm)
nv50_display_read_hw_or_state(dev, disp, nouveau_encoder(encoder));
}
drm_for_each_plane(plane, dev)
nv50_wndw_default_state(nv50_wndw(plane));
DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
}

View File

@@ -848,6 +848,28 @@ static const u64 nv50_cursor_format_modifiers[] = {
DRM_FORMAT_MOD_INVALID,
};
/*
* Setup defaults for the atomic wndw state
*/
void
nv50_wndw_default_state(struct nv50_wndw *wndw)
{
struct nv50_wndw_atom *armw = nv50_wndw_atom(wndw->plane.state);
const unsigned int blend_modes = wndw->func->blend_modes;
drm_modeset_lock_assert_held(&wndw->plane.mutex);
/* Ensure the plane's atomic state didn't default to a pixel_blend_mode we don't support */
if (blend_modes && (!(BIT(armw->state.pixel_blend_mode) & blend_modes))) {
if (blend_modes & BIT(DRM_MODE_BLEND_COVERAGE))
armw->state.pixel_blend_mode = DRM_MODE_BLEND_COVERAGE;
else if (blend_modes & BIT(DRM_MODE_BLEND_PREMULTI))
armw->state.pixel_blend_mode = DRM_MODE_BLEND_PREMULTI;
else if (blend_modes & BIT(DRM_MODE_BLEND_PIXEL_NONE))
armw->state.pixel_blend_mode = DRM_MODE_BLEND_PIXEL_NONE;
}
}
int
nv50_wndw_new_(const struct nv50_wndw_func *func, struct drm_device *dev,
enum drm_plane_type type, const char *name, int index,
@@ -908,13 +930,6 @@ nv50_wndw_new_(const struct nv50_wndw_func *func, struct drm_device *dev,
ret = drm_plane_create_alpha_property(&wndw->plane);
if (ret)
return ret;
ret = drm_plane_create_blend_mode_property(&wndw->plane,
BIT(DRM_MODE_BLEND_PIXEL_NONE) |
BIT(DRM_MODE_BLEND_PREMULTI) |
BIT(DRM_MODE_BLEND_COVERAGE));
if (ret)
return ret;
} else {
ret = drm_plane_create_zpos_immutable_property(&wndw->plane,
nv50_wndw_zpos_default(&wndw->plane));
@@ -922,6 +937,17 @@ nv50_wndw_new_(const struct nv50_wndw_func *func, struct drm_device *dev,
return ret;
}
/*
* DRM requires that we have a blend mode property for any type of plane that exposes color
* formats with an alpha channel. So do this, even if we don't actually have control for the
* blend property hooked up with blend_set.
*/
if (func->blend_modes) {
ret = drm_plane_create_blend_mode_property(&wndw->plane, func->blend_modes);
if (ret)
return ret;
}
return 0;
}

View File

@@ -1,6 +1,8 @@
#ifndef __NV50_KMS_WNDW_H__
#define __NV50_KMS_WNDW_H__
#define nv50_wndw(p) container_of((p), struct nv50_wndw, plane)
#include <drm/drm_blend.h>
#include "disp.h"
#include "atom.h"
#include "lut.h"
@@ -44,6 +46,7 @@ void nv50_wndw_flush_clr(struct nv50_wndw *, u32 *interlock, bool flush,
struct nv50_wndw_atom *);
void nv50_wndw_ntfy_enable(struct nv50_wndw *, struct nv50_wndw_atom *);
int nv50_wndw_wait_armed(struct nv50_wndw *, struct nv50_wndw_atom *);
void nv50_wndw_default_state(struct nv50_wndw *wndw);
struct nv50_wndw_func {
int (*acquire)(struct nv50_wndw *, struct nv50_wndw_atom *asyw,
@@ -74,6 +77,7 @@ struct nv50_wndw_func {
int (*image_clr)(struct nv50_wndw *);
int (*scale_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
int (*blend_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
unsigned int blend_modes;
int (*update)(struct nv50_wndw *, u32 *interlock);
};
@@ -139,4 +143,11 @@ int wndwca7e_new(struct nouveau_drm *, enum drm_plane_type, int, s32,
int nv50_wndw_new(struct nouveau_drm *, enum drm_plane_type, int index,
struct nv50_wndw **);
/* A set of blend modes supported by all wndws */
#define WNDW_BLEND_MODES \
( BIT(DRM_MODE_BLEND_COVERAGE) \
| BIT(DRM_MODE_BLEND_PREMULTI) \
| BIT(DRM_MODE_BLEND_PIXEL_NONE))
#endif

View File

@@ -343,6 +343,7 @@ wndwc37e = {
.image_set = wndwc37e_image_set,
.image_clr = wndwc37e_image_clr,
.blend_set = wndwc37e_blend_set,
.blend_modes = WNDW_BLEND_MODES,
.update = wndwc37e_update,
};

View File

@@ -231,6 +231,7 @@ wndwc57e = {
.image_set = wndwc57e_image_set,
.image_clr = wndwc37e_image_clr,
.blend_set = wndwc37e_blend_set,
.blend_modes = WNDW_BLEND_MODES,
.update = wndwc37e_update,
};

View File

@@ -95,6 +95,7 @@ wndwc67e = {
.image_set = wndwc67e_image_set,
.image_clr = wndwc37e_image_clr,
.blend_set = wndwc37e_blend_set,
.blend_modes = WNDW_BLEND_MODES,
.update = wndwc37e_update,
};

View File

@@ -231,6 +231,7 @@ wndwca7e = {
.image_set = wndwca7e_image_set,
.image_clr = wndwca7e_image_clr,
.blend_set = wndwc37e_blend_set,
.blend_modes = WNDW_BLEND_MODES,
.update = wndwc37e_update,
};

View File

@@ -408,6 +408,9 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
case NOUVEAU_FIFO_ENGINE_CE:
engine = NV_DEVICE_HOST_RUNLIST_ENGINES_CE;
break;
case NOUVEAU_FIFO_ENGINE_NVDEC:
engine = NV_DEVICE_HOST_RUNLIST_ENGINES_NVDEC;
break;
default:
return nouveau_abi16_put(abi16, -ENOSYS);
}
@@ -485,10 +488,13 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
goto done;
break;
case NV_DEVICE_INFO_V0_TURING:
ret = nvif_object_ctor(&chan->chan->user, "abi16CeWar", 0, TURING_DMA_COPY_A,
NULL, 0, &chan->ce);
if (ret)
goto done;
if (engine != NV_DEVICE_HOST_RUNLIST_ENGINES_NVDEC) {
ret = nvif_object_ctor(&chan->chan->user, "abi16CeWar",
0, TURING_DMA_COPY_A, NULL, 0,
&chan->ce);
if (ret)
goto done;
}
break;
default:
break;

View File

@@ -10,7 +10,7 @@
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 4
#define DRIVER_PATCHLEVEL 2
#define DRIVER_PATCHLEVEL 3
/*
* 1.1.1:
@@ -39,6 +39,8 @@
* - add variable page sizes and compression for Turing+
* 1.4.2:
* - tell userspace LPTE/SPTE races are fixed.
* 1.4.3:
* - VDEC contexts can be created.
*/
#include <linux/notifier.h>

View File

@@ -23,6 +23,7 @@
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <linux/cgroup_dmem.h>
#include <linux/limits.h>
#include <drm/ttm/ttm_range_manager.h>
@@ -188,6 +189,13 @@ nouveau_ttm_init_vram(struct nouveau_drm *drm)
man->func = &nouveau_vram_manager;
man->cg = drmm_cgroup_register_region(drm->dev, "vram",
&(struct dmem_cgroup_init){
.size = drm->gem.vram_available
});
if (IS_ERR(man->cg))
return PTR_ERR(man->cg);
ttm_resource_manager_init(man, &drm->ttm.bdev,
drm->gem.vram_available >> PAGE_SHIFT);
ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_VRAM, man);

View File

@@ -456,15 +456,10 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
timer_delete(&dsi->te_timer);
#endif
/* make a copy and unlock, so that isrs can unregister
* themselves */
memcpy(&dsi->isr_tables_copy, &dsi->isr_tables,
sizeof(dsi->isr_tables));
dsi_handle_isrs(&dsi->isr_tables, irqstatus, vcstatus, ciostatus);
spin_unlock(&dsi->irq_lock);
dsi_handle_isrs(&dsi->isr_tables_copy, irqstatus, vcstatus, ciostatus);
dsi_handle_irq_errors(dsi, irqstatus, vcstatus, ciostatus);
dsi_collect_irq_stats(dsi, irqstatus, vcstatus, ciostatus);

View File

@@ -379,8 +379,6 @@ struct dsi_data {
spinlock_t irq_lock;
struct dsi_isr_tables isr_tables;
/* space for a copy used by the interrupt handler */
struct dsi_isr_tables isr_tables_copy;
int update_vc;
#ifdef DSI_PERF_MEASURE

View File

@@ -144,6 +144,16 @@ struct panel_delay {
*/
unsigned int disable;
/**
* @pre_unprepare: Time for the end of video data to power off.
*
* The time (in milliseconds) that it needs to have passed between
* the end of valid video data from source and start powering off.
*
* This is T10-min on eDP timing diagrams. It is not common to set.
*/
unsigned int pre_unprepare;
/**
* @unprepare: Time to power down completely.
*
@@ -413,8 +423,12 @@ static int panel_edp_suspend(struct device *dev)
static int panel_edp_unprepare(struct drm_panel *panel)
{
struct panel_edp *p = to_panel_edp(panel);
int ret;
if (p->desc->delay.pre_unprepare)
msleep(p->desc->delay.pre_unprepare);
ret = pm_runtime_put_sync_suspend(panel->dev);
if (ret < 0)
return ret;
@@ -832,6 +846,13 @@ static int generic_edp_panel_probe(struct device *dev, struct panel_edp *panel)
return 0;
}
static void panel_edp_put_adapter(void *_adap)
{
struct i2c_adapter *adap = _adap;
i2c_put_adapter(adap);
}
static int panel_edp_probe(struct device *dev, const struct panel_desc *desc,
struct drm_dp_aux *aux)
{
@@ -874,11 +895,16 @@ static int panel_edp_probe(struct device *dev, const struct panel_desc *desc,
ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0);
if (ddc) {
panel->ddc = of_find_i2c_adapter_by_node(ddc);
panel->ddc = of_get_i2c_adapter_by_node(ddc);
of_node_put(ddc);
if (!panel->ddc)
return -EPROBE_DEFER;
err = devm_add_action_or_reset(dev, panel_edp_put_adapter,
panel->ddc);
if (err)
return err;
} else if (aux) {
panel->ddc = &aux->ddc;
}
@@ -890,7 +916,7 @@ static int panel_edp_probe(struct device *dev, const struct panel_desc *desc,
err = drm_panel_of_backlight(&panel->base);
if (err)
goto err_finished_ddc_init;
return err;
/*
* We use runtime PM for prepare / unprepare since those power the panel
@@ -937,9 +963,6 @@ static int panel_edp_probe(struct device *dev, const struct panel_desc *desc,
err_finished_pm_runtime:
pm_runtime_dont_use_autosuspend(dev);
pm_runtime_disable(dev);
err_finished_ddc_init:
if (panel->ddc && (!panel->aux || panel->ddc != &panel->aux->ddc))
put_device(&panel->ddc->dev);
return err;
}
@@ -983,8 +1006,6 @@ static void panel_edp_remove(struct device *dev)
pm_runtime_dont_use_autosuspend(dev);
pm_runtime_disable(dev);
if (panel->ddc && (!panel->aux || panel->ddc != &panel->aux->ddc))
put_device(&panel->ddc->dev);
drm_edid_free(panel->drm_edid);
panel->drm_edid = NULL;
@@ -1803,6 +1824,13 @@ static const struct panel_delay delay_80_500_e80_p2e200 = {
.prepare_to_enable = 200,
};
static const struct panel_delay delay_200_500_e80_pu100 = {
.hpd_absent = 200,
.unprepare = 500,
.enable = 80,
.pre_unprepare = 100,
};
static const struct panel_delay delay_100_500_e200 = {
.hpd_absent = 100,
.unprepare = 500,
@@ -2029,6 +2057,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a84, &delay_200_500_e50, "NV133WUM-T01"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, &delay_200_500_e50, "NV116WHM-N4C"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ae8, &delay_200_500_e50_p2e80, "NV140WUM-N41"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0af2, &delay_200_500_e50_p2e80, "NE140QDM-NX2"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b09, &delay_200_500_e50_po2e200, "NV140FHM-NZ"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b1e, &delay_200_500_e80, "NE140QDM-N6A"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b34, &delay_200_500_e80_d50, "NV122WUM-N41"),
@@ -2076,6 +2105,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1161, &delay_200_500_e80, "N116BCP-EA2"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1163, &delay_200_500_e80_d50, "N116BCJ-EAK"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1169, &delay_200_500_e80_d50, "N116BCN-EA1"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x116c, &delay_200_500_e80_d50, "N116BCP-EA2"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x116d, &delay_200_500_e80_d50, "N116BCP-EA2"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x117a, &delay_200_500_e80_d50, "N116BCL-EAK"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"),
@@ -2165,6 +2195,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('S', 'H', 'P', 0x154c, &delay_200_500_p2e100, "LQ116M1JW10"),
EDP_PANEL_ENTRY('S', 'H', 'P', 0x158f, &delay_200_500_p2e100, "LQ134Z1"),
EDP_PANEL_ENTRY('S', 'H', 'P', 0x1593, &delay_200_500_p2e100, "LQ134N1"),
EDP_PANEL_ENTRY('S', 'H', 'P', 0x15a7, &delay_200_500_e200, "LQ120P1JX51"),
EDP_PANEL_ENTRY('S', 'T', 'A', 0x0004, &delay_200_500_e200, "116KHD024006"),
EDP_PANEL_ENTRY('S', 'T', 'A', 0x0009, &delay_200_500_e250, "116QHD024002"),
@@ -2172,7 +2203,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('T', 'M', 'A', 0x0811, &delay_200_500_e80_d50, "TM140VDXP01-04"),
EDP_PANEL_ENTRY('T', 'M', 'A', 0x2094, &delay_200_500_e50_d100, "TL140VDMS03-01"),
EDP_PANEL_ENTRY('T', 'M', 'A', 0x2139, &delay_200_500_e50_d100, "TM156VDXP25"),
EDP_PANEL_ENTRY('T', 'M', 'A', 0x2139, &delay_200_500_e80_pu100, "TM156VDXP25"),
{ /* sentinal */ }
};

View File

@@ -25,22 +25,8 @@
#define ILI9805_SETEXTC_PARAMETER2 (0x98)
#define ILI9805_SETEXTC_PARAMETER3 (0x05)
#define ILI9805_INSTR(_delay, ...) { \
.delay = (_delay), \
.len = sizeof((u8[]) {__VA_ARGS__}), \
.data = (u8[]){__VA_ARGS__} \
}
struct ili9805_instr {
size_t len;
const u8 *data;
u32 delay;
};
struct ili9805_desc {
const char *name;
const struct ili9805_instr *init;
const size_t init_length;
void (*init)(struct mipi_dsi_multi_context *ctx);
const struct drm_display_mode *mode;
u32 width_mm;
u32 height_mm;
@@ -56,65 +42,80 @@ struct ili9805 {
struct gpio_desc *reset_gpio;
};
static const struct ili9805_instr gpm1780a0_init[] = {
ILI9805_INSTR(100, ILI9805_EXTCMD_CMD_SET_ENABLE_REG, ILI9805_SETEXTC_PARAMETER1,
ILI9805_SETEXTC_PARAMETER2, ILI9805_SETEXTC_PARAMETER3),
ILI9805_INSTR(100, 0xFD, 0x0F, 0x10, 0x44, 0x00),
ILI9805_INSTR(0, 0xf8, 0x18, 0x02, 0x02, 0x18, 0x02, 0x02, 0x30, 0x00,
0x00, 0x30, 0x00, 0x00, 0x30, 0x00, 0x00),
ILI9805_INSTR(0, 0xB8, 0x62),
ILI9805_INSTR(0, 0xF1, 0x00),
ILI9805_INSTR(0, 0xF2, 0x00, 0x58, 0x40),
ILI9805_INSTR(0, 0xF3, 0x60, 0x83, 0x04),
ILI9805_INSTR(0, 0xFC, 0x04, 0x0F, 0x01),
ILI9805_INSTR(0, 0xEB, 0x08, 0x0F),
ILI9805_INSTR(0, 0xe0, 0x00, 0x08, 0x0d, 0x0e, 0x0e, 0x0d, 0x0a, 0x08, 0x04,
0x08, 0x0d, 0x0f, 0x0b, 0x1c, 0x14, 0x0a),
ILI9805_INSTR(0, 0xe1, 0x00, 0x08, 0x0d, 0x0e, 0x0e, 0x0d, 0x0a, 0x08, 0x04,
0x08, 0x0d, 0x0f, 0x0b, 0x1c, 0x14, 0x0a),
ILI9805_INSTR(10, 0xc1, 0x13, 0x39, 0x19, 0x06),
ILI9805_INSTR(10, 0xc7, 0xe5),
ILI9805_INSTR(10, 0xB1, 0x00, 0x12, 0x14),
ILI9805_INSTR(10, 0xB4, 0x02),
ILI9805_INSTR(0, 0xBB, 0x14, 0x55),
ILI9805_INSTR(0, MIPI_DCS_SET_ADDRESS_MODE, 0x08),
ILI9805_INSTR(0, MIPI_DCS_SET_PIXEL_FORMAT, 0x77),
ILI9805_INSTR(0, 0x20),
ILI9805_INSTR(0, 0xB0, 0x01),
ILI9805_INSTR(0, 0xB6, 0x31, 0x00, 0xef),
ILI9805_INSTR(0, 0xDF, 0x23),
ILI9805_INSTR(0, 0xB9, 0x02, 0x00),
};
static void gpm1780a0_init(struct mipi_dsi_multi_context *ctx)
{
mipi_dsi_dcs_write_seq_multi(ctx, ILI9805_EXTCMD_CMD_SET_ENABLE_REG,
ILI9805_SETEXTC_PARAMETER1, ILI9805_SETEXTC_PARAMETER2,
ILI9805_SETEXTC_PARAMETER3);
mipi_dsi_msleep(ctx, 100);
mipi_dsi_dcs_write_seq_multi(ctx, 0xfd, 0x0f, 0x10, 0x44, 0x00);
mipi_dsi_msleep(ctx, 100);
mipi_dsi_dcs_write_seq_multi(ctx, 0xf8, 0x18, 0x02, 0x02, 0x18, 0x02, 0x02, 0x30, 0x00,
0x00, 0x30, 0x00, 0x00, 0x30, 0x00, 0x00);
mipi_dsi_dcs_write_seq_multi(ctx, 0xb8, 0x62);
mipi_dsi_dcs_write_seq_multi(ctx, 0xf1, 0x00);
mipi_dsi_dcs_write_seq_multi(ctx, 0xf2, 0x00, 0x58, 0x40);
mipi_dsi_dcs_write_seq_multi(ctx, 0xf3, 0x60, 0x83, 0x04);
mipi_dsi_dcs_write_seq_multi(ctx, 0xfc, 0x04, 0x0f, 0x01);
mipi_dsi_dcs_write_seq_multi(ctx, 0xeb, 0x08, 0x0f);
mipi_dsi_dcs_write_seq_multi(ctx, 0xe0, 0x00, 0x08, 0x0d, 0x0e, 0x0e, 0x0d, 0x0a, 0x08,
0x04, 0x08, 0x0d, 0x0f, 0x0b, 0x1c, 0x14, 0x0a);
mipi_dsi_dcs_write_seq_multi(ctx, 0xe1, 0x00, 0x08, 0x0d, 0x0e, 0x0e, 0x0d, 0x0a, 0x08,
0x04, 0x08, 0x0d, 0x0f, 0x0b, 0x1c, 0x14, 0x0a);
mipi_dsi_dcs_write_seq_multi(ctx, 0xc1, 0x13, 0x39, 0x19, 0x06);
mipi_dsi_msleep(ctx, 10);
mipi_dsi_dcs_write_seq_multi(ctx, 0xc7, 0xe5);
mipi_dsi_msleep(ctx, 10);
mipi_dsi_dcs_write_seq_multi(ctx, 0xb1, 0x00, 0x12, 0x14);
mipi_dsi_msleep(ctx, 10);
mipi_dsi_dcs_write_seq_multi(ctx, 0xb4, 0x02);
mipi_dsi_msleep(ctx, 10);
mipi_dsi_dcs_write_seq_multi(ctx, 0xbb, 0x14, 0x55);
mipi_dsi_dcs_write_seq_multi(ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x08);
mipi_dsi_dcs_set_pixel_format_multi(ctx, 0x77);
mipi_dsi_dcs_write_seq_multi(ctx, 0x20);
mipi_dsi_dcs_write_seq_multi(ctx, 0xb0, 0x01);
mipi_dsi_dcs_write_seq_multi(ctx, 0xb6, 0x31, 0x00, 0xef);
mipi_dsi_dcs_write_seq_multi(ctx, 0xdf, 0x23);
mipi_dsi_dcs_write_seq_multi(ctx, 0xb9, 0x02, 0x00);
}
static const struct ili9805_instr tm041xdhg01_init[] = {
ILI9805_INSTR(100, ILI9805_EXTCMD_CMD_SET_ENABLE_REG, ILI9805_SETEXTC_PARAMETER1,
ILI9805_SETEXTC_PARAMETER2, ILI9805_SETEXTC_PARAMETER3),
ILI9805_INSTR(100, 0xFD, 0x0F, 0x13, 0x44, 0x00),
ILI9805_INSTR(0, 0xf8, 0x18, 0x02, 0x02, 0x18, 0x02, 0x02, 0x30, 0x01,
0x01, 0x30, 0x01, 0x01, 0x30, 0x01, 0x01),
ILI9805_INSTR(0, 0xB8, 0x74),
ILI9805_INSTR(0, 0xF1, 0x00),
ILI9805_INSTR(0, 0xF2, 0x00, 0x58, 0x40),
ILI9805_INSTR(0, 0xFC, 0x04, 0x0F, 0x01),
ILI9805_INSTR(0, 0xEB, 0x08, 0x0F),
ILI9805_INSTR(0, 0xe0, 0x01, 0x0d, 0x15, 0x0e, 0x0f, 0x0f, 0x0b, 0x08, 0x04,
0x07, 0x0a, 0x0d, 0x0c, 0x15, 0x0f, 0x08),
ILI9805_INSTR(0, 0xe1, 0x01, 0x0d, 0x15, 0x0e, 0x0f, 0x0f, 0x0b, 0x08, 0x04,
0x07, 0x0a, 0x0d, 0x0c, 0x15, 0x0f, 0x08),
ILI9805_INSTR(10, 0xc1, 0x15, 0x03, 0x03, 0x31),
ILI9805_INSTR(10, 0xB1, 0x00, 0x12, 0x14),
ILI9805_INSTR(10, 0xB4, 0x02),
ILI9805_INSTR(0, 0xBB, 0x14, 0x55),
ILI9805_INSTR(0, MIPI_DCS_SET_ADDRESS_MODE, 0x0a),
ILI9805_INSTR(0, MIPI_DCS_SET_PIXEL_FORMAT, 0x77),
ILI9805_INSTR(0, 0x20),
ILI9805_INSTR(0, 0xB0, 0x00),
ILI9805_INSTR(0, 0xB6, 0x01),
ILI9805_INSTR(0, 0xc2, 0x11),
ILI9805_INSTR(0, 0x51, 0xFF),
ILI9805_INSTR(0, 0x53, 0x24),
ILI9805_INSTR(0, 0x55, 0x00),
};
static void tm041xdhg01_init(struct mipi_dsi_multi_context *ctx)
{
mipi_dsi_dcs_write_seq_multi(ctx, ILI9805_EXTCMD_CMD_SET_ENABLE_REG,
ILI9805_SETEXTC_PARAMETER1, ILI9805_SETEXTC_PARAMETER2,
ILI9805_SETEXTC_PARAMETER3);
mipi_dsi_msleep(ctx, 100);
mipi_dsi_dcs_write_seq_multi(ctx, 0xfd, 0x0f, 0x13, 0x44, 0x00);
mipi_dsi_msleep(ctx, 100);
mipi_dsi_dcs_write_seq_multi(ctx, 0xf8, 0x18, 0x02, 0x02, 0x18, 0x02, 0x02, 0x30, 0x01,
0x01, 0x30, 0x01, 0x01, 0x30, 0x01, 0x01);
mipi_dsi_dcs_write_seq_multi(ctx, 0xb8, 0x74);
mipi_dsi_dcs_write_seq_multi(ctx, 0xf1, 0x00);
mipi_dsi_dcs_write_seq_multi(ctx, 0xf2, 0x00, 0x58, 0x40);
mipi_dsi_dcs_write_seq_multi(ctx, 0xfc, 0x04, 0x0f, 0x01);
mipi_dsi_dcs_write_seq_multi(ctx, 0xeb, 0x08, 0x0f);
mipi_dsi_dcs_write_seq_multi(ctx, 0xe0, 0x01, 0x0d, 0x15, 0x0e, 0x0f, 0x0f, 0x0b, 0x08,
0x04, 0x07, 0x0a, 0x0d, 0x0c, 0x15, 0x0f, 0x08);
mipi_dsi_dcs_write_seq_multi(ctx, 0xe1, 0x01, 0x0d, 0x15, 0x0e, 0x0f, 0x0f, 0x0b, 0x08,
0x04, 0x07, 0x0a, 0x0d, 0x0c, 0x15, 0x0f, 0x08);
mipi_dsi_dcs_write_seq_multi(ctx, 0xc1, 0x15, 0x03, 0x03, 0x31);
mipi_dsi_msleep(ctx, 10);
mipi_dsi_dcs_write_seq_multi(ctx, 0xb1, 0x00, 0x12, 0x14);
mipi_dsi_msleep(ctx, 10);
mipi_dsi_dcs_write_seq_multi(ctx, 0xb4, 0x02);
mipi_dsi_msleep(ctx, 10);
mipi_dsi_dcs_write_seq_multi(ctx, 0xbb, 0x14, 0x55);
mipi_dsi_dcs_write_seq_multi(ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x0a);
mipi_dsi_dcs_set_pixel_format_multi(ctx, 0x77);
mipi_dsi_dcs_write_seq_multi(ctx, 0x20);
mipi_dsi_dcs_write_seq_multi(ctx, 0xb0, 0x00);
mipi_dsi_dcs_write_seq_multi(ctx, 0xb6, 0x01);
mipi_dsi_dcs_write_seq_multi(ctx, 0xc2, 0x11);
mipi_dsi_dcs_write_seq_multi(ctx, 0x51, 0xff);
mipi_dsi_dcs_write_seq_multi(ctx, 0x53, 0x24);
mipi_dsi_dcs_write_seq_multi(ctx, 0x55, 0x00);
}
static inline struct ili9805 *panel_to_ili9805(struct drm_panel *panel)
{
@@ -148,47 +149,24 @@ static int ili9805_power_on(struct ili9805 *ctx)
return 0;
}
static int ili9805_power_off(struct ili9805 *ctx)
static void ili9805_power_off(struct ili9805 *ctx)
{
gpiod_set_value(ctx->reset_gpio, 0);
regulator_disable(ctx->dvdd);
regulator_disable(ctx->avdd);
return 0;
}
static int ili9805_activate(struct ili9805 *ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
struct device *dev = &dsi->dev;
int i, ret;
struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
for (i = 0; i < ctx->desc->init_length; i++) {
const struct ili9805_instr *instr = &ctx->desc->init[i];
ctx->desc->init(&dsi_ctx);
ret = mipi_dsi_dcs_write_buffer(ctx->dsi, instr->data, instr->len);
if (ret < 0)
return ret;
mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
mipi_dsi_usleep_range(&dsi_ctx, 5000, 6000);
mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
if (instr->delay > 0)
msleep(instr->delay);
}
ret = mipi_dsi_dcs_exit_sleep_mode(ctx->dsi);
if (ret) {
dev_err(dev, "Failed to exit sleep mode (%d)\n", ret);
return ret;
}
usleep_range(5000, 6000);
ret = mipi_dsi_dcs_set_display_on(ctx->dsi);
if (ret) {
dev_err(dev, "Failed to set display ON (%d)\n", ret);
return ret;
}
return 0;
return dsi_ctx.accum_err;
}
static int ili9805_prepare(struct drm_panel *panel)
@@ -209,27 +187,13 @@ static int ili9805_prepare(struct drm_panel *panel)
return 0;
}
static int ili9805_deactivate(struct ili9805 *ctx)
static void ili9805_deactivate(struct ili9805 *ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
struct device *dev = &dsi->dev;
int ret;
struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
ret = mipi_dsi_dcs_set_display_off(ctx->dsi);
if (ret < 0) {
dev_err(dev, "Failed to set display OFF (%d)\n", ret);
return ret;
}
usleep_range(5000, 10000);
ret = mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
if (ret < 0) {
dev_err(dev, "Failed to enter sleep mode (%d)\n", ret);
return ret;
}
return 0;
mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
mipi_dsi_usleep_range(&dsi_ctx, 5000, 10000);
mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
}
static int ili9805_unprepare(struct drm_panel *panel)
@@ -271,7 +235,7 @@ static const struct drm_display_mode tm041xdhg01_timing = {
};
static int ili9805_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
struct drm_connector *connector)
{
struct ili9805 *ctx = panel_to_ili9805(panel);
struct drm_display_mode *mode;
@@ -368,7 +332,6 @@ static void ili9805_dsi_remove(struct mipi_dsi_device *dsi)
static const struct ili9805_desc gpm1780a0_desc = {
.init = gpm1780a0_init,
.init_length = ARRAY_SIZE(gpm1780a0_init),
.mode = &gpm1780a0_timing,
.width_mm = 65,
.height_mm = 65,
@@ -376,7 +339,6 @@ static const struct ili9805_desc gpm1780a0_desc = {
static const struct ili9805_desc tm041xdhg01_desc = {
.init = tm041xdhg01_init,
.init_length = ARRAY_SIZE(tm041xdhg01_init),
.mode = &tm041xdhg01_timing,
.width_mm = 42,
.height_mm = 96,

View File

@@ -2931,6 +2931,248 @@ static const struct jadard_panel_desc waveshare_10_1_inch_b_desc = {
MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS,
};
static int dcltek_dt300250_init_cmds(struct jadard *jadard)
{
struct mipi_dsi_multi_context dsi_ctx = { .dsi = jadard->dsi };
jd9365da_switch_page(&dsi_ctx, 0x00);
jadard_enable_standard_cmds(&dsi_ctx);
jd9365da_switch_page(&dsi_ctx, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x01, 0x2B);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x10);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x2B);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0C, 0x74);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0xCF);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1A, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1B, 0xCF);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1C, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0xFE);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x09);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x04);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3A, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3C, 0x5C);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3D, 0xFF);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3E, 0xFF);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3F, 0x7F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x02);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0xC8);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x42, 0x66);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x10);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x0F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x45, 0x28);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x02);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x8D);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0x0A);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5A, 0x29);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5B, 0x1A);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5D, 0x7F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5E, 0x65);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5F, 0x53);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x45);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x3E);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x30);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x33);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x3B);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x3C);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0x3F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x5D);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x49);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6A, 0x4D);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6B, 0x3D);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6C, 0x37);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6D, 0x28);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6E, 0x15);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6F, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x70, 0x7F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x71, 0x65);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x72, 0x53);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x73, 0x45);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x74, 0x3E);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0x30);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x33);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x3B);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x79, 0x3C);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7A, 0x3F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7B, 0x5D);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7C, 0x49);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7D, 0x4D);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7E, 0x3D);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7F, 0x44);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0x28);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x81, 0x15);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x82, 0x00);
jd9365da_switch_page(&dsi_ctx, 0x02);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x41);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x01, 0x5F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0x5F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x4B);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x5F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x5C);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x06, 0x5F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x07, 0x49);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x08, 0x5F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x5A);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0A, 0x5F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0B, 0x47);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0C, 0x5F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0D, 0x4F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0E, 0x5F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0F, 0x45);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x10, 0x5F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x11, 0x4D);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x12, 0x5F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x13, 0x5E);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x14, 0x51);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x15, 0x5F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x16, 0x40);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x17, 0x5F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x18, 0x5F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x19, 0x4A);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1A, 0x5F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1B, 0x5B);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1C, 0x5F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1D, 0x48);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1E, 0x5F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1F, 0x59);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x20, 0x5F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x21, 0x46);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x22, 0x5F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x23, 0x4E);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0x5F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x25, 0x44);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x26, 0x5F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x27, 0x4C);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x28, 0x5F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x29, 0x5E);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2A, 0x50);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2B, 0x5F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2C, 0x10);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2D, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2E, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2F, 0x0C);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x30, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x31, 0x04);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x32, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x33, 0x0E);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x34, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x06);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x36, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x19);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0x08);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3A, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3B, 0x1B);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3C, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3D, 0x0A);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3E, 0x1E);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3F, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x42, 0x11);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x45, 0x0D);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x46, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x47, 0x05);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x48, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x49, 0x0F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4A, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4B, 0x07);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4C, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4D, 0x1A);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4E, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4F, 0x09);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x51, 0x1C);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x52, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x53, 0x0B);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x54, 0x1E);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x56, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x1F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x58, 0x40);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5B, 0x10);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5C, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5D, 0x70);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5E, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5F, 0x02);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x70);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x02);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x06);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x4A);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x56);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x4F);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0xF7);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x01);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x06);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6A, 0x4A);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6B, 0x10);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6C, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6D, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6E, 0x00);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6F, 0x88);
jd9365da_switch_page(&dsi_ctx, 0x04);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x0E);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0xB3);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x60);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0e, 0x4A);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x58);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2b, 0x0F);
jd9365da_switch_page(&dsi_ctx, 0x05);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x15, 0x34);
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x16, 0x76);
jd9365da_switch_page(&dsi_ctx, 0x00);
mipi_dsi_msleep(&dsi_ctx, 120);
mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 120);
mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 20);
mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
return dsi_ctx.accum_err;
}
static const struct jadard_panel_desc dcltek_dt300250_desc = {
.mode_4ln = &(const struct drm_display_mode) {
.clock = (600 + 48 + 32 + 80) * (1600 + 18 + 6 + 23) * 60 / 1000,
.hdisplay = 600,
.hsync_start = 600 + 48,
.hsync_end = 600 + 48 + 32,
.htotal = 600 + 48 + 32 + 80,
.vdisplay = 1600,
.vsync_start = 1600 + 18,
.vsync_end = 1600 + 18 + 6,
.vtotal = 1600 + 18 + 6 + 23,
.width_mm = 83,
.height_mm = 221,
.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
},
.lanes = 4,
.format = MIPI_DSI_FMT_RGB888,
.init = dcltek_dt300250_init_cmds,
};
static int jadard_dsi_probe(struct mipi_dsi_device *dsi)
{
struct device *dev = &dsi->dev;
@@ -2950,7 +3192,8 @@ static int jadard_dsi_probe(struct mipi_dsi_device *dsi)
else
dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
MIPI_DSI_MODE_VIDEO_BURST |
MIPI_DSI_MODE_NO_EOT_PACKET;
MIPI_DSI_MODE_NO_EOT_PACKET |
MIPI_DSI_MODE_LPM;
dsi->format = desc->format;
dsi->lanes = desc->lanes;
@@ -3036,6 +3279,10 @@ static const struct of_device_id jadard_of_match[] = {
.compatible = "chongzhou,cz101b4001",
.data = &cz101b4001_desc
},
{
.compatible = "dcltek,dt300250",
.data = &dcltek_dt300250_desc
},
{
.compatible = "kingdisplay,kd101ne3-40ti",
.data = &kingdisplay_kd101ne3_40ti_desc

View File

@@ -429,11 +429,9 @@ static int novatek_probe(struct mipi_dsi_device *dsi)
ctx->dsi[i]->mode_flags = desc->mode_flags;
ctx->dsi[i]->dsc = &ctx->dsc;
ret = devm_mipi_dsi_attach(dev, ctx->dsi[i]);
if (ret < 0) {
drm_panel_remove(&ctx->panel);
if (ret < 0)
return dev_err_probe(dev, ret,
"Failed to attach to DSI host\n");
}
}
if (desc->has_dcs_backlight) {

View File

@@ -912,6 +912,36 @@ static const struct panel_desc ampire_am_800480l1tmqw_t00h = {
.connector_type = DRM_MODE_CONNECTOR_DPI,
};
static const struct display_timing ampire_am_800480n3tzqw_00h_timing = {
.pixelclock = {23000000, 25000000, 27000000},
.hactive = { 800, 800, 800 },
.hfront_porch = { 4, 8, 48 },
.hback_porch = { 4, 8, 48 },
.hsync_len = { 2, 8, 8 },
.vactive = { 480, 480, 480 },
.vfront_porch = { 4, 8, 12 },
.vback_porch = { 4, 8, 12 },
.vsync_len = { 2, 4, 8 },
.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE |
DISPLAY_FLAGS_SYNC_POSEDGE,
};
static const struct panel_desc ampire_am_800480n3tzqw_00h = {
.timings = &ampire_am_800480n3tzqw_00h_timing,
.num_timings = 1,
.bpc = 8,
.size = {
.width = 108,
.height = 65,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
.bus_flags = DRM_BUS_FLAG_DE_HIGH |
DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE |
DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE,
.connector_type = DRM_MODE_CONNECTOR_DPI,
};
static const struct panel_desc ampire_am800480r3tmqwa1h = {
.modes = &ampire_am800480r3tmqwa1h_mode,
.num_modes = 1,
@@ -5648,6 +5678,9 @@ static const struct of_device_id platform_of_match[] = {
}, {
.compatible = "ampire,am-800480l1tmqw-t00h",
.data = &ampire_am_800480l1tmqw_t00h,
}, {
.compatible = "ampire,am-800480n3tzqw-00h",
.data = &ampire_am_800480n3tzqw_00h,
}, {
.compatible = "ampire,am800480r3tmqwa1h",
.data = &ampire_am800480r3tmqwa1h,

View File

@@ -47,6 +47,7 @@
#define ST7703_CMD_SETCABC 0xC8
#define ST7703_CMD_SETPANEL 0xCC
#define ST7703_CMD_SETGAMMA 0xE0
#define ST7703_CMD_UNKNOWN_E1 0xE1
#define ST7703_CMD_SETEQ 0xE3
#define ST7703_CMD_SETGIP1 0xE9
#define ST7703_CMD_SETGIP2 0xEA
@@ -673,6 +674,100 @@ static const struct st7703_panel_desc gameforcechi_desc = {
.init_sequence = gameforcechi_init_sequence,
};
static void ayaneo_pocket_ds_lower_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
{
/* Init sequence extracted from the AYANEO Pocket DS BSP kernel. */
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xf1, 0x12,
0x87);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0x00, 0x01,
0x78);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF, 0x10, 0x10,
0x28, 0x28, 0x03, 0xff, 0x00, 0x00, 0x00,
0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x0a, 0x0a);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x90, 0x90);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT, 0x76,
0x22, 0xf0, 0x13);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI, 0x33, 0x81,
0x05, 0xf9, 0x0e, 0x0e, 0x20, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25,
0x00, 0x91, 0x0a, 0x00, 0x00, 0x01, 0x4f,
0x01, 0x00, 0x00, 0x37);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x47);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x10,
0x00, 0x80, 0x04);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR, 0x73, 0x73,
0x50, 0x50, 0x00, 0x00, 0x12, 0x73, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x55, 0x00,
0x32, 0x32, 0x77, 0xf1, 0xf7, 0xf7, 0xcc,
0xcc, 0x7f, 0x7f, 0x11, 0x11, 0x00, 0x00,
0x32);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETIO, 0xb8, 0x00,
0x0a, 0x10, 0x01, 0x09, 0x00, 0x00, 0xed,
0xc5, 0x00, 0xa5);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCABC, 0x10, 0x40,
0x1e, 0x03);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0b);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA, 0x00, 0x00,
0x00, 0x25, 0x31, 0x3f, 0x26, 0x29, 0x04,
0x08, 0x0d, 0x0e, 0x12, 0x0f, 0x11, 0x12,
0x18, 0x00, 0x00, 0x00, 0x25, 0x31, 0x3f,
0x26, 0x29, 0x04, 0x08, 0x0d, 0x0e, 0x12,
0x0f, 0x11, 0x12, 0x18);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_E1, 0x11, 0x11,
0x91, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ, 0x07, 0x07,
0x0b, 0x0b, 0x0b, 0x0b, 0x00, 0x00, 0x00,
0x00, 0xff, 0x84, 0xc0, 0x10);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1, 0xc8, 0x10,
0x04, 0x04, 0x02, 0x80, 0x81, 0x12, 0x31,
0x23, 0x2f, 0x80, 0x80, 0x81, 0x27, 0x20,
0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0f, 0x00, 0x00, 0x00, 0x44, 0x00,
0x88, 0xff, 0x00, 0x22, 0x44, 0x66, 0x88,
0x88, 0x88, 0x55, 0x11, 0x88, 0xff, 0x11,
0x33, 0x55, 0x77, 0x88, 0x88, 0x88, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x11, 0x55, 0xff, 0x88,
0x77, 0x55, 0x33, 0x11, 0x88, 0x88, 0x88,
0x00, 0x44, 0xff, 0x88, 0x66, 0x44, 0x22,
0x00, 0x88, 0x88, 0x88, 0x23, 0x00, 0x00,
0x00, 0xec, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x20, 0x80, 0x81, 0x00,
0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_EF, 0xff, 0xff,
0x01);
}
static const struct drm_display_mode ayaneo_pocket_ds_lower_mode = {
.hdisplay = 768,
.hsync_start = 768 + 110,
.hsync_end = 768 + 110 + 45,
.htotal = 768 + 110 + 45 + 110,
.vdisplay = 1024,
.vsync_start = 1024 + 18,
.vsync_end = 1024 + 18 + 6,
.vtotal = 1024 + 18 + 6 + 16,
.clock = 65946,
.width_mm = 76,
.height_mm = 102,
};
static const struct st7703_panel_desc ayaneo_pocket_ds_lower_desc = {
.mode = &ayaneo_pocket_ds_lower_mode,
.lanes = 4,
.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
.format = MIPI_DSI_FMT_RGB888,
.init_sequence = ayaneo_pocket_ds_lower_init_sequence,
};
static int st7703_enable(struct drm_panel *panel)
{
struct st7703 *ctx = panel_to_st7703(panel);
@@ -916,6 +1011,7 @@ static void st7703_remove(struct mipi_dsi_device *dsi)
static const struct of_device_id st7703_of_match[] = {
{ .compatible = "anbernic,rg353v-panel-v2", .data = &rg353v2_desc },
{ .compatible = "ayaneo,pocket-ds-lower-panel", .data = &ayaneo_pocket_ds_lower_desc },
{ .compatible = "gameforce,chi-panel", .data = &gameforcechi_desc },
{ .compatible = "powkiddy,rgb10max3-panel", .data = &rgb10max3_panel_desc },
{ .compatible = "powkiddy,rgb30-panel", .data = &rgb30panel_desc },

View File

@@ -35,6 +35,7 @@ struct tdo_tl070wsh30_panel *to_tdo_tl070wsh30_panel(struct drm_panel *panel)
static int tdo_tl070wsh30_panel_prepare(struct drm_panel *panel)
{
struct tdo_tl070wsh30_panel *tdo_tl070wsh30 = to_tdo_tl070wsh30_panel(panel);
struct mipi_dsi_multi_context dsi_ctx = { .dsi = tdo_tl070wsh30->link };
int err;
err = regulator_enable(tdo_tl070wsh30->supply);
@@ -51,44 +52,27 @@ static int tdo_tl070wsh30_panel_prepare(struct drm_panel *panel)
msleep(200);
err = mipi_dsi_dcs_exit_sleep_mode(tdo_tl070wsh30->link);
if (err < 0) {
dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 200);
mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 20);
if (dsi_ctx.accum_err)
regulator_disable(tdo_tl070wsh30->supply);
return err;
}
msleep(200);
err = mipi_dsi_dcs_set_display_on(tdo_tl070wsh30->link);
if (err < 0) {
dev_err(panel->dev, "failed to set display on: %d\n", err);
regulator_disable(tdo_tl070wsh30->supply);
return err;
}
msleep(20);
return 0;
return dsi_ctx.accum_err;
}
static int tdo_tl070wsh30_panel_unprepare(struct drm_panel *panel)
{
struct tdo_tl070wsh30_panel *tdo_tl070wsh30 = to_tdo_tl070wsh30_panel(panel);
int err;
err = mipi_dsi_dcs_set_display_off(tdo_tl070wsh30->link);
if (err < 0)
dev_err(panel->dev, "failed to set display off: %d\n", err);
struct mipi_dsi_multi_context dsi_ctx = { .dsi = tdo_tl070wsh30->link };
mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
/* Reset error to continue power-down sequence even if display off failed */
dsi_ctx.accum_err = 0;
usleep_range(10000, 11000);
err = mipi_dsi_dcs_enter_sleep_mode(tdo_tl070wsh30->link);
if (err < 0) {
dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
return err;
}
mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
usleep_range(10000, 11000);
regulator_disable(tdo_tl070wsh30->supply);

View File

@@ -1824,7 +1824,7 @@ static int panthor_probe(struct platform_device *pdev)
ptdev = devm_drm_dev_alloc(&pdev->dev, &panthor_drm_driver,
struct panthor_device, base);
if (IS_ERR(ptdev))
return -ENOMEM;
return PTR_ERR(ptdev);
platform_set_drvdata(pdev, ptdev);

View File

@@ -697,7 +697,8 @@ static int panthor_fw_read_build_info(struct panthor_device *ptdev,
return ret;
if (hdr.meta_start > fw->size ||
hdr.meta_start + hdr.meta_size > fw->size) {
hdr.meta_size > fw->size - hdr.meta_start ||
hdr.meta_size <= header_len) {
drm_err(&ptdev->base, "Firmware build info corrupt\n");
/* We don't need the build info, so continue */
return 0;
@@ -877,14 +878,15 @@ static int panthor_init_cs_iface(struct panthor_device *ptdev,
struct panthor_fw_csg_iface *csg_iface = panthor_fw_get_csg_iface(ptdev, csg_idx);
struct panthor_fw_cs_iface *cs_iface = &ptdev->fw->iface.streams[csg_idx][cs_idx];
u64 shared_section_sz = panthor_kernel_bo_size(ptdev->fw->shared_section->mem);
u32 iface_offset = CSF_GROUP_CONTROL_OFFSET +
(csg_idx * glb_iface->control->group_stride) +
u64 iface_offset = CSF_GROUP_CONTROL_OFFSET +
((u64)csg_idx * glb_iface->control->group_stride) +
CSF_STREAM_CONTROL_OFFSET +
(cs_idx * csg_iface->control->stream_stride);
((u64)cs_idx * csg_iface->control->stream_stride);
struct panthor_fw_cs_iface *first_cs_iface =
panthor_fw_get_cs_iface(ptdev, 0, 0);
if (iface_offset + sizeof(*cs_iface) >= shared_section_sz)
if (iface_offset > shared_section_sz ||
sizeof(*cs_iface->control) > shared_section_sz - iface_offset)
return -EINVAL;
spin_lock_init(&cs_iface->lock);
@@ -932,10 +934,12 @@ static int panthor_init_csg_iface(struct panthor_device *ptdev,
struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev);
struct panthor_fw_csg_iface *csg_iface = &ptdev->fw->iface.groups[csg_idx];
u64 shared_section_sz = panthor_kernel_bo_size(ptdev->fw->shared_section->mem);
u32 iface_offset = CSF_GROUP_CONTROL_OFFSET + (csg_idx * glb_iface->control->group_stride);
u64 iface_offset = CSF_GROUP_CONTROL_OFFSET +
((u64)csg_idx * glb_iface->control->group_stride);
unsigned int i;
if (iface_offset + sizeof(*csg_iface) >= shared_section_sz)
if (iface_offset > shared_section_sz ||
sizeof(*csg_iface->control) > shared_section_sz - iface_offset)
return -EINVAL;
spin_lock_init(&csg_iface->lock);
@@ -985,11 +989,15 @@ static u32 panthor_get_instr_features(struct panthor_device *ptdev)
static int panthor_fw_init_ifaces(struct panthor_device *ptdev)
{
struct panthor_fw_global_iface *glb_iface = &ptdev->fw->iface.global;
u64 shared_section_sz = panthor_kernel_bo_size(ptdev->fw->shared_section->mem);
unsigned int i;
if (!ptdev->fw->shared_section->mem->kmap)
return -EINVAL;
if (sizeof(*glb_iface->control) > shared_section_sz)
return -EINVAL;
spin_lock_init(&glb_iface->lock);
glb_iface->control = ptdev->fw->shared_section->mem->kmap;

View File

@@ -306,10 +306,13 @@ struct panthor_vm {
/** @kernel_auto_va.start: Start of the automatic VA-range for kernel BOs. */
u64 start;
/** @kernel_auto_va.size: Size of the automatic VA-range for kernel BOs. */
/** @kernel_auto_va.end: End of the automatic VA-range for kernel BOs. */
u64 end;
} kernel_auto_va;
/** @user_va_range: Upper boundary of VAs VM users can map objects against. */
u64 user_va_range;
/** @as: Address space related fields. */
struct {
/**
@@ -2892,6 +2895,8 @@ panthor_vm_create(struct panthor_device *ptdev, bool for_mcu,
va_range = full_va_range;
}
vm->user_va_range = kernel_va_start;
mutex_init(&vm->mm_lock);
drm_mm_init(&vm->mm, kernel_va_start, kernel_va_size);
vm->kernel_auto_va.start = auto_kernel_va_start;
@@ -2980,6 +2985,10 @@ panthor_vm_bind_prepare_op_ctx(struct drm_file *file,
if (!IS_ALIGNED(op->va | op->size | op->bo_offset, vm_pgsz))
return -EINVAL;
/* We don't allow mappings that overlap with kbo's reserved range */
if (range_overflows(op->va, op->size, vm->user_va_range))
return -EINVAL;
switch (op->flags & DRM_PANTHOR_VM_BIND_OP_TYPE_MASK) {
case DRM_PANTHOR_VM_BIND_OP_TYPE_MAP:
if (!(op->flags & DRM_PANTHOR_VM_BIND_OP_MAP_SPARSE)) {

View File

@@ -14,6 +14,7 @@
#include <linux/bits.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/math.h>
#include <linux/property.h>
#include <linux/pwm.h>
#include <linux/regulator/consumer.h>
@@ -140,6 +141,11 @@
#define SSD133X_SET_PRECHARGE_VOLTAGE 0xbb
#define SSD133X_SET_VCOMH_VOLTAGE 0xbe
/* ssd133x A/B/C channel contrast at full brightness (white balance) */
#define SSD133X_DEFAULT_CONTRAST_A 0x91
#define SSD133X_DEFAULT_CONTRAST_B 0x50
#define SSD133X_DEFAULT_CONTRAST_C 0x7d
#define MAX_CONTRAST 255
const struct ssd130x_deviceinfo ssd130x_variants[] = {
@@ -582,12 +588,37 @@ static int ssd132x_init(struct ssd130x_device *ssd130x)
return ssd130x_run_cmd_seq(ssd130x, cmds);
}
static int ssd133x_init(struct ssd130x_device *ssd130x)
/* Scale a channel's white-balance calibration contrast by the requested brightness */
static u8 ssd130x_scale_contrast(u8 calibration, u32 brightness)
{
return DIV_ROUND_CLOSEST(calibration * brightness, MAX_CONTRAST);
}
/*
* The A/B/C contrast channels drive sub-pixels whose OLED materials differ
* in luminous efficiency, so the per-channel values are a white-balance
* calibration. Scale them by the requested brightness instead of
* overwriting them, to keep the white point while dimming.
*/
static int ssd133x_set_contrast(struct ssd130x_device *ssd130x, u32 brightness)
{
const u8 cmds[] = {
2, SSD133X_CONTRAST_A, 0x91,
2, SSD133X_CONTRAST_B, 0x50,
2, SSD133X_CONTRAST_C, 0x7d,
2, SSD133X_CONTRAST_A,
ssd130x_scale_contrast(SSD133X_DEFAULT_CONTRAST_A, brightness),
2, SSD133X_CONTRAST_B,
ssd130x_scale_contrast(SSD133X_DEFAULT_CONTRAST_B, brightness),
2, SSD133X_CONTRAST_C,
ssd130x_scale_contrast(SSD133X_DEFAULT_CONTRAST_C, brightness),
0,
};
return ssd130x_run_cmd_seq(ssd130x, cmds);
}
static int ssd133x_init(struct ssd130x_device *ssd130x)
{
int ret;
const u8 cmds[] = {
2, SSD133X_SET_MASTER_CURRENT, 0x06,
3, SSD133X_SET_COL_RANGE, 0x00, ssd130x->width - 1,
3, SSD133X_SET_ROW_RANGE, 0x00, ssd130x->height - 1,
@@ -614,6 +645,10 @@ static int ssd133x_init(struct ssd130x_device *ssd130x)
0,
};
ret = ssd133x_set_contrast(ssd130x, ssd130x->contrast);
if (ret < 0)
return ret;
return ssd130x_run_cmd_seq(ssd130x, cmds);
}
@@ -1676,8 +1711,25 @@ static int ssd130x_update_bl(struct backlight_device *bdev)
return 0;
}
static const struct backlight_ops ssd130xfb_bl_ops = {
.update_status = ssd130x_update_bl,
static int ssd133x_update_bl(struct backlight_device *bdev)
{
struct ssd130x_device *ssd130x = bl_get_data(bdev);
ssd130x->contrast = backlight_get_brightness(bdev);
return ssd133x_set_contrast(ssd130x, ssd130x->contrast);
}
static const struct backlight_ops ssd130xfb_bl_ops[] = {
[SSD130X_FAMILY] = {
.update_status = ssd130x_update_bl,
},
[SSD132X_FAMILY] = {
.update_status = ssd130x_update_bl,
},
[SSD133X_FAMILY] = {
.update_status = ssd133x_update_bl,
},
};
static void ssd130x_parse_properties(struct ssd130x_device *ssd130x)
@@ -1884,7 +1936,8 @@ struct ssd130x_device *ssd130x_probe(struct device *dev, struct regmap *regmap)
return ERR_PTR(ret);
bl = devm_backlight_device_register(dev, dev_name(dev), dev, ssd130x,
&ssd130xfb_bl_ops, NULL);
&ssd130xfb_bl_ops[ssd130x->device_info->family_id],
NULL);
if (IS_ERR(bl))
return ERR_PTR(dev_err_probe(dev, PTR_ERR(bl),
"Unable to register backlight device\n"));

View File

@@ -208,7 +208,7 @@ struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm,
planes = sunxi_engine_layers_init(drm, engine);
if (IS_ERR(planes)) {
dev_err(drm->dev, "Couldn't create the planes\n");
return NULL;
return ERR_CAST(planes);
}
/* find primary and cursor planes for drm_crtc_init_with_planes */

View File

@@ -289,6 +289,8 @@ static void sun4i_drv_traverse_endpoints(struct endpoint_list *list,
kfifo_put(&list->fifo, remote);
}
of_node_put(port);
}
static int sun4i_drv_add_endpoints(struct device *dev,
@@ -394,6 +396,7 @@ static int sun4i_drv_probe(struct platform_device *pdev)
/* process this endpoint */
ret = sun4i_drv_add_endpoints(&pdev->dev, &list, &match,
endpoint);
of_node_put(endpoint);
/* sun4i_drv_add_endpoints can fail to allocate memory */
if (ret < 0)

View File

@@ -14,24 +14,8 @@
#include "sun4i_drv.h"
#include "sun4i_framebuffer.h"
static int sun4i_de_atomic_check(struct drm_device *dev,
struct drm_atomic_commit *state)
{
int ret;
ret = drm_atomic_helper_check_modeset(dev, state);
if (ret)
return ret;
ret = drm_atomic_normalize_zpos(dev, state);
if (ret)
return ret;
return drm_atomic_helper_check_planes(dev, state);
}
static const struct drm_mode_config_funcs sun4i_de_mode_config_funcs = {
.atomic_check = sun4i_de_atomic_check,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
.fb_create = drm_gem_fb_create,
};
@@ -46,6 +30,7 @@ void sun4i_framebuffer_init(struct drm_device *drm)
drm->mode_config.max_width = 8192;
drm->mode_config.max_height = 8192;
drm->mode_config.normalize_zpos = true;
drm->mode_config.funcs = &sun4i_de_mode_config_funcs;
drm->mode_config.helper_private = &sun4i_de_mode_config_helpers;

View File

@@ -160,7 +160,7 @@ static void sun4i_hdmi_enable(struct drm_encoder *encoder,
drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
val |= SUN4I_HDMI_PKT_CTRL_TYPE(0, SUN4I_HDMI_PKT_AVI);
val = SUN4I_HDMI_PKT_CTRL_TYPE(0, SUN4I_HDMI_PKT_AVI);
val |= SUN4I_HDMI_PKT_CTRL_TYPE(1, SUN4I_HDMI_PKT_END);
writel(val, hdmi->base + SUN4I_HDMI_PKT_CTRL_REG(0));

View File

@@ -717,9 +717,11 @@ void sun4i_tcon_mode_set(struct sun4i_tcon *tcon,
case DRM_MODE_ENCODER_DSI:
/* DSI is tied to special case of CPU interface */
sun4i_tcon0_mode_set_cpu(tcon, encoder, mode);
sun4i_tcon_set_mux(tcon, 0, encoder);
break;
case DRM_MODE_ENCODER_LVDS:
sun4i_tcon0_mode_set_lvds(tcon, encoder, mode);
sun4i_tcon_set_mux(tcon, 0, encoder);
break;
case DRM_MODE_ENCODER_NONE:
sun4i_tcon0_mode_set_rgb(tcon, encoder, mode);
@@ -970,6 +972,7 @@ static int sun4i_tcon_of_get_id_from_port(struct device_node *port)
continue;
ret = of_property_read_u32(remote, "reg", &reg);
of_node_put(remote);
if (ret)
continue;
@@ -1409,7 +1412,7 @@ static int sun8i_r40_tcon_tv_set_mux(struct sun4i_tcon *tcon,
{
struct device_node *port, *remote;
struct platform_device *pdev;
int id, ret;
int id, ret = 0;
/* find TCON TOP platform device and TCON id */
@@ -1432,21 +1435,20 @@ static int sun8i_r40_tcon_tv_set_mux(struct sun4i_tcon *tcon,
if (IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP) &&
encoder->encoder_type == DRM_MODE_ENCODER_TMDS) {
ret = sun8i_tcon_top_set_hdmi_src(&pdev->dev, id);
if (ret) {
put_device(&pdev->dev);
return ret;
}
if (ret)
goto out_put_device;
}
if (IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP)) {
ret = sun8i_tcon_top_de_config(&pdev->dev, tcon->id, id);
if (ret) {
put_device(&pdev->dev);
return ret;
}
if (ret)
goto out_put_device;
}
return 0;
out_put_device:
put_device(&pdev->dev);
return ret;
}
static const struct sun4i_tcon_quirks sun4i_a10_quirks = {

View File

@@ -86,6 +86,8 @@ static u32 sun8i_dw_hdmi_find_possible_crtcs(struct drm_device *drm,
of_node_put(remote_port);
}
}
of_node_put(port);
} else {
crtcs = drm_of_find_possible_crtcs(drm, node);
}

View File

@@ -91,7 +91,7 @@ static const struct dw_hdmi_mpll_config sun50i_h6_mpll_cfg[] = {
},
}, {
594000000, {
{ 0x1a40, 0x0003 },
{ 0x1a7c, 0x0003 },
{ 0x3b4c, 0x0003 },
{ 0x5a64, 0x0003 },
},

View File

@@ -785,7 +785,7 @@ static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
.de_type = SUN8I_MIXER_DE2,
.vi_scaler_num = 2,
.scaler_mask = 0x3,
.scanline_yuv = 2048,
.scanline_yuv = 1024,
},
.de_type = SUN8I_MIXER_DE2,
.mod_rate = 150000000,

View File

@@ -25,6 +25,49 @@ static bool sun8i_tcon_top_node_is_tcon_top(struct device_node *node)
return !!of_match_node(sun8i_tcon_top_of_table, node);
}
static unsigned int sun8i_tcon_top_get_tcon_map(struct device_node *node)
{
static const u32 out_ports[] = {
TCON_TOP_MIXER0_OUT_PORT,
TCON_TOP_MIXER1_OUT_PORT,
};
unsigned int i, map = 0;
for (i = 0; i < ARRAY_SIZE(out_ports); i++) {
struct device_node *port;
port = of_graph_get_port_by_id(node, out_ports[i]);
if (!port)
continue;
for_each_of_graph_port_endpoint(port, ep) {
struct of_endpoint endpoint;
if (of_graph_parse_endpoint(ep, &endpoint))
continue;
if (endpoint.id < TCON_TOP_PORT_TCON_NUM)
map |= BIT(endpoint.id);
}
of_node_put(port);
}
return map;
}
static unsigned int sun8i_tcon_top_park_index(struct sun8i_tcon_top *tcon_top,
int tcon)
{
unsigned int candidates;
candidates = tcon_top->tcon_map & ~BIT(tcon);
if (!candidates)
candidates = GENMASK(TCON_TOP_PORT_TCON_NUM - 1, 0) & ~BIT(tcon);
return ffs(candidates) - 1;
}
int sun8i_tcon_top_set_hdmi_src(struct device *dev, int tcon)
{
struct sun8i_tcon_top *tcon_top = dev_get_drvdata(dev);
@@ -57,6 +100,7 @@ EXPORT_SYMBOL(sun8i_tcon_top_set_hdmi_src);
int sun8i_tcon_top_de_config(struct device *dev, int mixer, int tcon)
{
struct sun8i_tcon_top *tcon_top = dev_get_drvdata(dev);
u32 mixer_msk, other_msk;
unsigned long flags;
u32 reg;
@@ -70,21 +114,27 @@ int sun8i_tcon_top_de_config(struct device *dev, int mixer, int tcon)
return -EINVAL;
}
if (tcon > 3) {
dev_err(dev, "TCON index is too high!\n");
if (tcon < 0 || tcon >= TCON_TOP_PORT_TCON_NUM) {
dev_err(dev, "TCON index is invalid!\n");
return -EINVAL;
}
mixer_msk = mixer ? TCON_TOP_PORT_DE1_MSK : TCON_TOP_PORT_DE0_MSK;
other_msk = mixer ? TCON_TOP_PORT_DE0_MSK : TCON_TOP_PORT_DE1_MSK;
spin_lock_irqsave(&tcon_top->reg_lock, flags);
reg = readl(tcon_top->regs + TCON_TOP_PORT_SEL_REG);
if (mixer == 0) {
reg &= ~TCON_TOP_PORT_DE0_MSK;
reg |= FIELD_PREP(TCON_TOP_PORT_DE0_MSK, tcon);
} else {
reg &= ~TCON_TOP_PORT_DE1_MSK;
reg |= FIELD_PREP(TCON_TOP_PORT_DE1_MSK, tcon);
reg &= ~mixer_msk;
reg |= field_prep(mixer_msk, tcon);
if (field_get(other_msk, reg) == tcon) {
reg &= ~other_msk;
reg |= field_prep(other_msk,
sun8i_tcon_top_park_index(tcon_top, tcon));
}
writel(reg, tcon_top->regs + TCON_TOP_PORT_SEL_REG);
spin_unlock_irqrestore(&tcon_top->reg_lock, flags);
@@ -143,6 +193,7 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master,
return -ENOMEM;
clk_data->num = CLK_NUM;
tcon_top->clk_data = clk_data;
tcon_top->tcon_map = sun8i_tcon_top_get_tcon_map(dev->of_node);
spin_lock_init(&tcon_top->reg_lock);
@@ -175,10 +226,6 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master,
goto err_assert_reset;
}
/*
* At least on H6, some registers have some bits set by default
* which may cause issues. Clear them here.
*/
writel(0, regs + TCON_TOP_PORT_SEL_REG);
writel(0, regs + TCON_TOP_GATE_SRC_REG);

View File

@@ -14,6 +14,10 @@
#define TCON_TOP_PORT_SEL_REG 0x1C
#define TCON_TOP_PORT_DE0_MSK GENMASK(1, 0)
#define TCON_TOP_PORT_DE1_MSK GENMASK(5, 4)
#define TCON_TOP_PORT_TCON_NUM 4
#define TCON_TOP_MIXER0_OUT_PORT 1
#define TCON_TOP_MIXER1_OUT_PORT 3
#define TCON_TOP_GATE_SRC_REG 0x20
#define TCON_TOP_HDMI_SRC_MSK GENMASK(29, 28)
@@ -29,6 +33,8 @@ struct sun8i_tcon_top {
void __iomem *regs;
struct reset_control *rst;
unsigned int tcon_map;
/*
* spinlock is used to synchronize access to same
* register where multiple clock gates can be set.

View File

@@ -894,20 +894,26 @@ static void sun8i_vi_scaler_set_coeff(struct regmap *map, u32 base,
lan3coefftab32_left[offset + i]);
regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF1(base, i),
lan3coefftab32_right[offset + i]);
}
offset = sun8i_vi_scaler_coef_index(vstep) *
SUN8I_VI_SCALER_COEFF_COUNT;
for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++)
regmap_write(map, SUN8I_SCALER_VSU_YVCOEFF(base, i),
lan2coefftab32[offset + i]);
offset = sun8i_vi_scaler_coef_index(hstep / format->hsub) *
SUN8I_VI_SCALER_COEFF_COUNT;
for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) {
regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF0(base, i),
ch_left[offset + i]);
regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF1(base, i),
ch_right[offset + i]);
}
offset = sun8i_vi_scaler_coef_index(hstep) *
offset = sun8i_vi_scaler_coef_index(vstep / format->vsub) *
SUN8I_VI_SCALER_COEFF_COUNT;
for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) {
regmap_write(map, SUN8I_SCALER_VSU_YVCOEFF(base, i),
lan2coefftab32[offset + i]);
for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++)
regmap_write(map, SUN8I_SCALER_VSU_CVCOEFF(base, i),
cy[offset + i]);
}
}
void sun8i_vi_scaler_enable(struct sun8i_layer *layer, bool enable)
@@ -969,6 +975,8 @@ void sun8i_vi_scaler_setup(struct sun8i_layer *layer,
regmap_write(layer->regs,
SUN50I_SCALER_VSU_SCALE_MODE(base), val);
regmap_write(layer->regs,
SUN50I_SCALER_VSU_GLB_ALPHA(base), 0xff);
}
regmap_write(layer->regs,

View File

@@ -36,6 +36,7 @@
#define SUN50I_SCALER_VSU_EDSCL_CTRL(base) ((base) + 0x28)
#define SUN50I_SCALER_VSU_ANGLE_THR(base) ((base) + 0x2c)
#define SUN8I_SCALER_VSU_OUTSIZE(base) ((base) + 0x40)
#define SUN50I_SCALER_VSU_GLB_ALPHA(base) ((base) + 0x44)
#define SUN8I_SCALER_VSU_YINSIZE(base) ((base) + 0x80)
#define SUN8I_SCALER_VSU_YHSTEP(base) ((base) + 0x88)
#define SUN8I_SCALER_VSU_YVSTEP(base) ((base) + 0x8c)

View File

@@ -488,6 +488,118 @@ int ttm_bo_evict_first(struct ttm_device *bdev, struct ttm_resource_manager *man
return ret;
}
struct ttm_bo_alloc_state {
/** @charge_pool: The memory pool the resource is charged to */
struct dmem_cgroup_pool_state *charge_pool;
/** @limit_pool: Which pool limit we should test against */
struct dmem_cgroup_pool_state *limit_pool;
/** @in_evict: Whether we are currently evicting buffers */
bool in_evict;
/** @may_try_low: If only unprotected BOs, i.e. BOs whose cgroup
* is exceeding its dmem low/min protection, should be considered for eviction
*/
bool may_try_low;
};
/**
* ttm_bo_alloc_at_place - Attempt allocating a BO's backing store in a place
*
* @bo: The buffer to allocate the backing store of
* @place: The place to attempt allocation in
* @ctx: ttm_operation_ctx associated with this allocation
* @force_space: If we should evict buffers to force space
* @res: On allocation success, the resulting struct ttm_resource.
* @alloc_state: Object holding allocation state such as charged cgroups.
*
* Returns:
* -EBUSY: No space available, but allocation should be retried with ttm_bo_evict_alloc.
* -ENOSPC: No space available, allocation should not be retried.
* -ERESTARTSYS: An interruptible sleep was interrupted by a signal.
*
*/
static int ttm_bo_alloc_at_place(struct ttm_buffer_object *bo,
const struct ttm_place *place,
bool force_space,
struct ttm_resource **res,
struct ttm_bo_alloc_state *alloc_state)
{
bool may_evict;
int ret;
may_evict = !alloc_state->in_evict && force_space &&
place->mem_type != TTM_PL_SYSTEM;
if (!alloc_state->charge_pool) {
ret = ttm_resource_try_charge(bo, place, &alloc_state->charge_pool,
force_space ? &alloc_state->limit_pool
: NULL);
if (ret) {
/*
* -EAGAIN means the charge failed, which we treat
* like an allocation failure. Therefore, return an
* error code indicating the allocation failed -
* either -EBUSY if the allocation should be
* retried with eviction, or -ENOSPC if there should
* be no second attempt.
*/
if (!alloc_state->in_evict)
alloc_state->may_try_low = may_evict;
if (ret == -EAGAIN)
ret = may_evict ? -EBUSY : -ENOSPC;
return ret;
}
}
/*
* cgroup protection plays a special role in eviction.
* Conceptually, protection of memory via the dmem cgroup controller
* entitles the protected cgroup to use a certain amount of memory.
* There are two types of protection - the 'low' limit is a
* "best-effort" protection, whereas the 'min' limit provides a hard
* guarantee that memory within the cgroup's allowance will not be
* evicted under any circumstance.
*
* To faithfully model this concept in TTM, we also need to take cgroup
* protection into account when allocating. When allocation in one
* place fails, TTM will default to trying other places first before
* evicting.
* If the allocation is covered by dmem cgroup protection, however,
* this prevents the allocation from using the memory it is "entitled"
* to. To make sure unprotected allocations cannot push new protected
* allocations out of places they are "entitled" to use, we should
* evict buffers not covered by any cgroup protection, if this
* allocation is covered by cgroup protection.
*
* Buffers covered by 'min' protection are a special case - the 'min'
* limit is a stronger guarantee than 'low', and thus buffers protected
* by 'low' but not 'min' should also be considered for eviction.
* Buffers protected by 'min' will never be considered for eviction
* anyway, so the regular eviction path should be triggered here.
* Buffers protected by 'low' but not 'min' will take a special
* eviction path that only evicts buffers covered by neither 'low' or
* 'min' protections.
*/
if (!alloc_state->in_evict) {
may_evict |= dmem_cgroup_below_min(NULL, alloc_state->charge_pool);
alloc_state->may_try_low = may_evict;
may_evict |= dmem_cgroup_below_low(NULL, alloc_state->charge_pool);
}
ret = ttm_resource_alloc(bo, place, res, alloc_state->charge_pool);
if (ret) {
if (ret == -ENOSPC && may_evict)
ret = -EBUSY;
return ret;
}
/*
* Ownership of charge_pool has been transferred to the TTM resource,
* don't make the caller think we still hold a reference to it.
*/
alloc_state->charge_pool = NULL;
return 0;
}
/**
* struct ttm_bo_evict_walk - Parameters for the evict walk.
*/
@@ -503,24 +615,70 @@ struct ttm_bo_evict_walk {
/** @evicted: Number of successful evictions. */
unsigned long evicted;
/** @limit_pool: Which pool limit we should test against */
struct dmem_cgroup_pool_state *limit_pool;
/** @try_low: Whether we should attempt to evict BO's with low watermark threshold */
bool try_low;
/** @hit_low: If we cannot evict a bo when @try_low is false (first pass) */
bool hit_low;
/** @alloc_state: State associated with the allocation attempt. */
struct ttm_bo_alloc_state *alloc_state;
};
static s64 ttm_bo_evict_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo)
{
struct ttm_bo_evict_walk *evict_walk =
container_of(walk, typeof(*evict_walk), walk);
struct dmem_cgroup_pool_state *limit_pool, *ancestor = NULL;
s64 bo_size = bo->base.size;
bool evict_valuable;
s64 lret;
if (!dmem_cgroup_state_evict_valuable(evict_walk->limit_pool, bo->resource->css,
evict_walk->try_low, &evict_walk->hit_low))
/*
* If may_try_low is not set, then we're trying to evict unprotected
* buffers in favor of a protected allocation for charge_pool. Explicitly skip
* buffers belonging to the same cgroup here - that cgroup is definitely protected,
* even though dmem_cgroup_state_evict_valuable would allow the eviction because a
* cgroup is always allowed to evict from itself even if it is protected.
*/
if (!evict_walk->alloc_state->may_try_low &&
bo->resource->css == evict_walk->alloc_state->charge_pool)
return 0;
limit_pool = evict_walk->alloc_state->limit_pool;
/*
* If there is no explicit limit pool, find the root of the shared subtree between
* evictor and evictee. This is important so that recursive protection rules can
* apply properly: Recursive protection distributes cgroup protection afforded
* to a parent cgroup but not used explicitly by a child cgroup between all child
* cgroups (see docs of effective_protection in mm/page_counter.c). However, when
* direct siblings compete for memory, siblings that were explicitly protected
* should get prioritized over siblings that weren't. This only happens correctly
* when the root of the shared subtree is passed to
* dmem_cgroup_state_evict_valuable. Otherwise, the effective-protection
* calculation cannot distinguish direct siblings from unrelated subtrees and the
* calculated protection ends up wrong.
*/
if (!limit_pool) {
ancestor = dmem_cgroup_get_common_ancestor(bo->resource->css,
evict_walk->alloc_state->charge_pool);
limit_pool = ancestor;
}
evict_valuable = dmem_cgroup_state_evict_valuable(limit_pool, bo->resource->css,
evict_walk->try_low,
&evict_walk->hit_low);
if (ancestor)
dmem_cgroup_pool_state_put(ancestor);
if (!evict_valuable)
return 0;
/*
* evict_walk->place is NULL in cgroup drain mode. Drivers'
* eviction_valuable() callbacks must handle a NULL place, treating it
* as "any placement": the TTM base implementation already does so via
* ttm_resource_intersects().
*/
if (bo->pin_count || !bo->bdev->funcs->eviction_valuable(bo, evict_walk->place))
return 0;
@@ -536,11 +694,17 @@ static s64 ttm_bo_evict_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *
goto out;
evict_walk->evicted++;
if (evict_walk->res)
lret = ttm_resource_alloc(evict_walk->evictor, evict_walk->place,
evict_walk->res, NULL);
if (lret == 0)
return 1;
if (evict_walk->res) {
lret = ttm_bo_alloc_at_place(evict_walk->evictor,
evict_walk->place, false,
evict_walk->res,
evict_walk->alloc_state);
if (lret == 0)
return 1;
} else {
/* Cgroup drain: return bytes freed for byte-denominated progress. */
return bo_size;
}
out:
/* Errors that should terminate the walk. */
if (lret == -ENOSPC)
@@ -560,7 +724,7 @@ static int ttm_bo_evict_alloc(struct ttm_device *bdev,
struct ttm_operation_ctx *ctx,
struct ww_acquire_ctx *ticket,
struct ttm_resource **res,
struct dmem_cgroup_pool_state *limit_pool)
struct ttm_bo_alloc_state *state)
{
struct ttm_bo_evict_walk evict_walk = {
.walk = {
@@ -573,15 +737,21 @@ static int ttm_bo_evict_alloc(struct ttm_device *bdev,
.place = place,
.evictor = evictor,
.res = res,
.limit_pool = limit_pool,
.alloc_state = state,
};
s64 lret;
state->in_evict = true;
evict_walk.walk.arg.trylock_only = true;
lret = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man, 1);
/* One more attempt if we hit low limit? */
if (!lret && evict_walk.hit_low) {
/* If we failed to find enough BOs to evict, but we skipped over
* some BOs because they were covered by dmem low protection, retry
* evicting these protected BOs too, except if we're told not to
* consider protected BOs at all.
*/
if (!lret && evict_walk.hit_low && state->may_try_low) {
evict_walk.try_low = true;
lret = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man, 1);
}
@@ -602,11 +772,13 @@ static int ttm_bo_evict_alloc(struct ttm_device *bdev,
} while (!lret && evict_walk.evicted);
/* We hit the low limit? Try once more */
if (!lret && evict_walk.hit_low && !evict_walk.try_low) {
if (!lret && evict_walk.hit_low && !evict_walk.try_low &&
state->may_try_low) {
evict_walk.try_low = true;
goto retry;
}
out:
state->in_evict = false;
if (lret < 0)
return lret;
if (lret == 0)
@@ -614,6 +786,86 @@ static int ttm_bo_evict_alloc(struct ttm_device *bdev,
return 0;
}
/**
* ttm_bo_evict_cgroup() - Evict buffer objects charged to a specific cgroup.
* @bdev: The TTM device.
* @man: The resource manager whose LRU to walk.
* @limit_pool: The cgroup pool state whose members should be evicted.
* @target_bytes: Number of bytes to free.
* @ctx: The TTM operation context.
*
* Walk the LRU of @man and evict buffer objects that are charged to the
* cgroup identified by @limit_pool, until at least @target_bytes have been
* freed. Mirrors the two-pass (trylock -> sleeping-lock, low-watermark)
* strategy used by ttm_bo_evict_alloc().
*
* Return: >= @target_bytes on full success, 0..target_bytes-1 if partial,
* negative error code on fatal error.
*/
s64 ttm_bo_evict_cgroup(struct ttm_device *bdev,
struct ttm_resource_manager *man,
struct dmem_cgroup_pool_state *limit_pool,
s64 target_bytes,
struct ttm_operation_ctx *ctx)
{
struct ttm_bo_evict_walk evict_walk = {
.walk = {
.ops = &ttm_evict_walk_ops,
.arg = { .ctx = ctx },
},
.alloc_state = &(struct ttm_bo_alloc_state) {
.limit_pool = limit_pool,
.in_evict = true,
},
/* place, evictor, res left NULL: selects cgroup drain mode */
};
s64 lret, pass;
evict_walk.walk.arg.trylock_only = true;
lret = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man, target_bytes);
if (lret < 0 || lret >= target_bytes)
return lret;
/* Second pass: also evict BOs at the low watermark. */
if (evict_walk.hit_low) {
evict_walk.try_low = true;
pass = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man,
target_bytes - lret);
if (pass < 0)
return pass;
lret += pass;
if (lret >= target_bytes)
return lret;
}
/* Full sleeping-lock pass for remaining target. */
evict_walk.try_low = evict_walk.hit_low = false;
evict_walk.walk.arg.trylock_only = false;
retry:
evict_walk.walk.arg.sleeping_lock = true;
do {
evict_walk.evicted = 0;
pass = ttm_lru_walk_for_evict(&evict_walk.walk, bdev, man,
target_bytes - lret);
if (pass < 0) {
lret = pass;
goto out;
}
lret += pass;
} while (lret < target_bytes && evict_walk.evicted);
/* One more attempt if we hit the low limit during sleeping-lock pass. */
if (lret < target_bytes && evict_walk.hit_low && !evict_walk.try_low) {
evict_walk.try_low = true;
goto retry;
}
out:
return lret;
}
EXPORT_SYMBOL(ttm_bo_evict_cgroup);
/**
* ttm_bo_pin - Pin the buffer object.
* @bo: The buffer object to pin
@@ -724,9 +976,8 @@ static int ttm_bo_alloc_resource(struct ttm_buffer_object *bo,
for (i = 0; i < placement->num_placement; ++i) {
const struct ttm_place *place = &placement->placement[i];
struct dmem_cgroup_pool_state *limit_pool = NULL;
struct ttm_bo_alloc_state alloc_state = {};
struct ttm_resource_manager *man;
bool may_evict;
man = ttm_manager_type(bdev, place->mem_type);
if (!man || !ttm_resource_manager_used(man))
@@ -736,25 +987,30 @@ static int ttm_bo_alloc_resource(struct ttm_buffer_object *bo,
TTM_PL_FLAG_FALLBACK))
continue;
may_evict = (force_space && place->mem_type != TTM_PL_SYSTEM);
ret = ttm_resource_alloc(bo, place, res, force_space ? &limit_pool : NULL);
if (ret) {
if (ret != -ENOSPC) {
dmem_cgroup_pool_state_put(limit_pool);
return ret;
}
if (!may_evict) {
dmem_cgroup_pool_state_put(limit_pool);
continue;
}
ret = ttm_bo_alloc_at_place(bo, place, force_space, res,
&alloc_state);
if (ret == -ENOSPC) {
dmem_cgroup_uncharge(alloc_state.charge_pool, bo->base.size);
dmem_cgroup_pool_state_put(alloc_state.limit_pool);
continue;
} else if (ret == -EBUSY) {
ret = ttm_bo_evict_alloc(bdev, man, place, bo, ctx,
ticket, res, limit_pool);
dmem_cgroup_pool_state_put(limit_pool);
if (ret == -EBUSY)
continue;
if (ret)
ticket, res, &alloc_state);
dmem_cgroup_pool_state_put(alloc_state.limit_pool);
if (ret) {
dmem_cgroup_uncharge(alloc_state.charge_pool,
bo->base.size);
if (ret == -EBUSY)
continue;
return ret;
}
} else if (ret) {
dmem_cgroup_uncharge(alloc_state.charge_pool, bo->base.size);
dmem_cgroup_pool_state_put(alloc_state.limit_pool);
return ret;
}
ret = ttm_bo_add_pipelined_eviction_fences(bo, man, ctx->no_wait_gpu);

View File

@@ -999,7 +999,8 @@ __ttm_bo_lru_cursor_next(struct ttm_bo_lru_cursor *curs)
bo = res->bo;
if (ttm_lru_walk_trylock(curs, bo))
bo_locked = true;
else if (!arg->ticket || arg->ctx->no_wait_gpu || arg->trylock_only)
else if ((!arg->ticket && !arg->sleeping_lock) || arg->ctx->no_wait_gpu ||
arg->trylock_only)
continue;
if (!ttm_bo_get_unless_zero(bo)) {

Some files were not shown because too many files have changed in this diff Show More