Merge tag 'drm-misc-next-2025-09-11' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next

drm-misc-next for v6.18:

UAPI Changes:

- Provide 'boot_display' attribute on boot-up devices

amdxdma:
- Add ioctl DRM_IOCTL_AMDXDNA_GET_ARRAY

Cross-subsystem Changes:

bindings:
- Add Mayqueen vendor prefix mayqueen-

pci:
- vgaarb: Use screen_info helpers

Core Changes:

ttm:
- Add interface to populate buffers

Driver Changes:

amdgpu:
- Pre-populate exported buffers

ast:
- Clean up detection of DRAM config

bochs:
- Clean up

bridge:
- adv7511: Write full Audio infoframe
- ite6263: Support vendor-specific infoframes
- simple: Add support for Realtek RTD2171 DP-to-HDMI plus DT bindings
- Clean up

gma500:
- Clean up

nouveau:
- Pre-populate exported buffers

panel:
- edp: Add support for additonal mt8189 Chromebook panels
- lvds: Add DT bindings for EDT ETML0700Z8DHA
- Clean up

pixpaper:
- Add support for Mayqueen Pixpaper plus DT bindings

rcar-du:
- Use RUNTIME_PM_OPS
- Add support for DSI commands

vkms:
- Support variants of ARGB8888, ARGB16161616, RGB565, RGB888 and P01x
- Spport YUV with 16-bit components

xe:
- Pre-populate exported buffers

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

From: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://lore.kernel.org/r/20250911091737.GA39831@linux.fritz.box
This commit is contained in:
Dave Airlie
2025-09-12 12:56:19 +10:00
46 changed files with 2419 additions and 486 deletions

View File

@@ -0,0 +1,8 @@
What: /sys/class/drm/.../boot_display
Date: January 2026
Contact: Linux DRI developers <dri-devel@vger.kernel.org>
Description:
This file indicates that displays connected to the device were
used to display the boot sequence. If a display connected to
the device was used to display the boot sequence the file will
be present and contain "1".

View File

@@ -29,6 +29,7 @@ properties:
- adi,adv7123
- dumb-vga-dac
- radxa,ra620
- realtek,rtd2171
- ti,opa362
- ti,ths8134
- ti,ths8135

View File

@@ -0,0 +1,63 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/mayqueen,pixpaper.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Mayqueen Pixpaper e-ink display panel
maintainers:
- LiangCheng Wang <zaq14760@gmail.com>
description:
The Pixpaper is an e-ink display panel controlled via an SPI interface.
The panel has a resolution of 122x250 pixels and requires GPIO pins for
reset, busy, and data/command control.
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
properties:
compatible:
const: mayqueen,pixpaper
reg:
maxItems: 1
spi-max-frequency:
maximum: 1000000
default: 1000000
reset-gpios:
maxItems: 1
busy-gpios:
maxItems: 1
dc-gpios:
maxItems: 1
required:
- compatible
- reg
- reset-gpios
- busy-gpios
- dc-gpios
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
display@0 {
compatible = "mayqueen,pixpaper";
reg = <0>;
spi-max-frequency = <1000000>;
reset-gpios = <&gpio1 17 GPIO_ACTIVE_HIGH>;
busy-gpios = <&gpio1 18 GPIO_ACTIVE_HIGH>;
dc-gpios = <&gpio1 19 GPIO_ACTIVE_HIGH>;
};
};

View File

@@ -48,6 +48,8 @@ properties:
- auo,g084sn05
# Chunghwa Picture Tubes Ltd. 7" WXGA (800x1280) TFT LCD LVDS panel
- chunghwa,claa070wp03xg
# EDT ETML0700Z8DHA 7.0" Full HD (1920x1080) color TFT LCD LVDS panel
- edt,etml0700z8dha
# EDT ETML0700Z9NDHA 7.0" WSVGA (1024x600) color TFT LCD LVDS panel
- edt,etml0700z9ndha
# HannStar Display Corp. HSD101PWW2 10.1" WXGA (1280x800) LVDS panel

View File

@@ -933,6 +933,8 @@ patternProperties:
description: Maxim Integrated Products
"^maxlinear,.*":
description: MaxLinear Inc.
"^mayqueen,.*":
description: Mayqueen Technologies Ltd.
"^mbvl,.*":
description: Mobiveil Inc.
"^mcube,.*":

View File

@@ -1243,7 +1243,7 @@ F: drivers/spi/spi-amd.c
F: drivers/spi/spi-amd.h
AMD XDNA DRIVER
M: Min Ma <min.ma@amd.com>
M: Min Ma <mamin506@gmail.com>
M: Lizhi Hou <lizhi.hou@amd.com>
L: dri-devel@lists.freedesktop.org
S: Supported
@@ -7490,7 +7490,6 @@ F: drivers/soc/ti/smartreflex.c
F: include/linux/power/smartreflex.h
DRM ACCEL DRIVERS FOR INTEL VPU
M: Jacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>
M: Maciej Falkowski <maciej.falkowski@linux.intel.com>
M: Karol Wachowski <karol.wachowski@linux.intel.com>
L: dri-devel@lists.freedesktop.org
@@ -7877,6 +7876,13 @@ T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
F: Documentation/devicetree/bindings/display/repaper.txt
F: drivers/gpu/drm/tiny/repaper.c
DRM DRIVER FOR PIXPAPER E-INK PANEL
M: LiangCheng Wang <zaq14760@gmail.com>
L: dri-devel@lists.freedesktop.org
S: Maintained
F: Documentation/devicetree/bindings/display/mayqueen,pixpaper.yaml
F: drivers/gpu/drm/tiny/pixpaper.c
DRM DRIVER FOR QEMU'S CIRRUS DEVICE
M: Dave Airlie <airlied@redhat.com>
M: Gerd Hoffmann <kraxel@redhat.com>

View File

@@ -6,7 +6,7 @@
struct device;
#if defined(CONFIG_STI_CORE)
#if defined(CONFIG_STI_CORE) && defined(CONFIG_VIDEO)
bool video_is_primary_device(struct device *dev);
#define video_is_primary_device video_is_primary_device
#endif

View File

@@ -19,8 +19,10 @@ static inline pgprot_t pgprot_framebuffer(pgprot_t prot,
#define pgprot_framebuffer pgprot_framebuffer
#endif
#ifdef CONFIG_VIDEO
bool video_is_primary_device(struct device *dev);
#define video_is_primary_device video_is_primary_device
#endif
static inline void fb_memcpy_fromio(void *to, const volatile void __iomem *from, size_t n)
{

View File

@@ -13,8 +13,10 @@ pgprot_t pgprot_framebuffer(pgprot_t prot,
unsigned long offset);
#define pgprot_framebuffer pgprot_framebuffer
#ifdef CONFIG_VIDEO
bool video_is_primary_device(struct device *dev);
#define video_is_primary_device video_is_primary_device
#endif
#include <asm-generic/video.h>

View File

@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/screen_info.h>
#include <linux/vgaarb.h>
#include <asm/video.h>
@@ -27,6 +28,11 @@ EXPORT_SYMBOL(pgprot_framebuffer);
bool video_is_primary_device(struct device *dev)
{
#ifdef CONFIG_SCREEN_INFO
struct screen_info *si = &screen_info;
struct resource res[SCREEN_INFO_MAX_RESOURCES];
ssize_t i, numres;
#endif
struct pci_dev *pdev;
if (!dev_is_pci(dev))
@@ -34,7 +40,24 @@ bool video_is_primary_device(struct device *dev)
pdev = to_pci_dev(dev);
return (pdev == vga_default_device());
if (!pci_is_display(pdev))
return false;
if (pdev == vga_default_device())
return true;
#ifdef CONFIG_SCREEN_INFO
numres = screen_info_resources(si, res, ARRAY_SIZE(res));
for (i = 0; i < numres; ++i) {
if (!(res[i].flags & IORESOURCE_MEM))
continue;
if (pci_find_resource(pdev, &res[i]))
return true;
}
#endif
return false;
}
EXPORT_SYMBOL(video_is_primary_device);

View File

@@ -785,11 +785,12 @@ static int aie2_get_clock_metadata(struct amdxdna_client *client,
static int aie2_hwctx_status_cb(struct amdxdna_hwctx *hwctx, void *arg)
{
struct amdxdna_drm_query_hwctx *tmp __free(kfree) = NULL;
struct amdxdna_drm_get_info *get_info_args = arg;
struct amdxdna_drm_query_hwctx __user *buf;
struct amdxdna_drm_hwctx_entry *tmp __free(kfree) = NULL;
struct amdxdna_drm_get_array *array_args = arg;
struct amdxdna_drm_hwctx_entry __user *buf;
u32 size;
if (get_info_args->buffer_size < sizeof(*tmp))
if (!array_args->num_element)
return -EINVAL;
tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
@@ -802,14 +803,23 @@ static int aie2_hwctx_status_cb(struct amdxdna_hwctx *hwctx, void *arg)
tmp->num_col = hwctx->num_col;
tmp->command_submissions = hwctx->priv->seq;
tmp->command_completions = hwctx->priv->completed;
tmp->pasid = hwctx->client->pasid;
tmp->priority = hwctx->qos.priority;
tmp->gops = hwctx->qos.gops;
tmp->fps = hwctx->qos.fps;
tmp->dma_bandwidth = hwctx->qos.dma_bandwidth;
tmp->latency = hwctx->qos.latency;
tmp->frame_exec_time = hwctx->qos.frame_exec_time;
tmp->state = AMDXDNA_HWCTX_STATE_ACTIVE;
buf = u64_to_user_ptr(get_info_args->buffer);
buf = u64_to_user_ptr(array_args->buffer);
size = min(sizeof(*tmp), array_args->element_size);
if (copy_to_user(buf, tmp, sizeof(*tmp)))
if (copy_to_user(buf, tmp, size))
return -EFAULT;
get_info_args->buffer += sizeof(*tmp);
get_info_args->buffer_size -= sizeof(*tmp);
array_args->buffer += size;
array_args->num_element--;
return 0;
}
@@ -817,23 +827,24 @@ static int aie2_hwctx_status_cb(struct amdxdna_hwctx *hwctx, void *arg)
static int aie2_get_hwctx_status(struct amdxdna_client *client,
struct amdxdna_drm_get_info *args)
{
struct amdxdna_drm_get_array array_args;
struct amdxdna_dev *xdna = client->xdna;
struct amdxdna_drm_get_info info_args;
struct amdxdna_client *tmp_client;
int ret;
drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock));
info_args.buffer = args->buffer;
info_args.buffer_size = args->buffer_size;
array_args.element_size = sizeof(struct amdxdna_drm_query_hwctx);
array_args.buffer = args->buffer;
array_args.num_element = args->buffer_size / array_args.element_size;
list_for_each_entry(tmp_client, &xdna->client_list, node) {
ret = amdxdna_hwctx_walk(tmp_client, &info_args, aie2_hwctx_status_cb);
ret = amdxdna_hwctx_walk(tmp_client, &array_args,
aie2_hwctx_status_cb);
if (ret)
break;
}
args->buffer_size = (u32)(info_args.buffer - args->buffer);
args->buffer_size -= (u32)(array_args.buffer - args->buffer);
return ret;
}
@@ -877,6 +888,58 @@ static int aie2_get_info(struct amdxdna_client *client, struct amdxdna_drm_get_i
return ret;
}
static int aie2_query_ctx_status_array(struct amdxdna_client *client,
struct amdxdna_drm_get_array *args)
{
struct amdxdna_drm_get_array array_args;
struct amdxdna_dev *xdna = client->xdna;
struct amdxdna_client *tmp_client;
int ret;
drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock));
array_args.element_size = min(args->element_size,
sizeof(struct amdxdna_drm_hwctx_entry));
array_args.buffer = args->buffer;
array_args.num_element = args->num_element * args->element_size /
array_args.element_size;
list_for_each_entry(tmp_client, &xdna->client_list, node) {
ret = amdxdna_hwctx_walk(tmp_client, &array_args,
aie2_hwctx_status_cb);
if (ret)
break;
}
args->element_size = array_args.element_size;
args->num_element = (u32)((array_args.buffer - args->buffer) /
args->element_size);
return ret;
}
static int aie2_get_array(struct amdxdna_client *client,
struct amdxdna_drm_get_array *args)
{
struct amdxdna_dev *xdna = client->xdna;
int ret, idx;
if (!drm_dev_enter(&xdna->ddev, &idx))
return -ENODEV;
switch (args->param) {
case DRM_AMDXDNA_HW_CONTEXT_ALL:
ret = aie2_query_ctx_status_array(client, args);
break;
default:
XDNA_ERR(xdna, "Not supported request parameter %u", args->param);
ret = -EOPNOTSUPP;
}
XDNA_DBG(xdna, "Got param %d", args->param);
drm_dev_exit(idx);
return ret;
}
static int aie2_set_power_mode(struct amdxdna_client *client,
struct amdxdna_drm_set_state *args)
{
@@ -926,15 +989,16 @@ static int aie2_set_state(struct amdxdna_client *client,
}
const struct amdxdna_dev_ops aie2_ops = {
.init = aie2_init,
.fini = aie2_fini,
.resume = aie2_hw_resume,
.suspend = aie2_hw_suspend,
.get_aie_info = aie2_get_info,
.set_aie_state = aie2_set_state,
.hwctx_init = aie2_hwctx_init,
.hwctx_fini = aie2_hwctx_fini,
.hwctx_config = aie2_hwctx_config,
.cmd_submit = aie2_cmd_submit,
.init = aie2_init,
.fini = aie2_fini,
.resume = aie2_hw_resume,
.suspend = aie2_hw_suspend,
.get_aie_info = aie2_get_info,
.set_aie_state = aie2_set_state,
.hwctx_init = aie2_hwctx_init,
.hwctx_fini = aie2_hwctx_fini,
.hwctx_config = aie2_hwctx_config,
.cmd_submit = aie2_cmd_submit,
.hmm_invalidate = aie2_hmm_invalidate,
.get_array = aie2_get_array,
};

View File

@@ -26,6 +26,13 @@ MODULE_FIRMWARE("amdnpu/17f0_10/npu.sbin");
MODULE_FIRMWARE("amdnpu/17f0_11/npu.sbin");
MODULE_FIRMWARE("amdnpu/17f0_20/npu.sbin");
/*
* 0.0: Initial version
* 0.1: Support getting all hardware contexts by DRM_IOCTL_AMDXDNA_GET_ARRAY
*/
#define AMDXDNA_DRIVER_MAJOR 0
#define AMDXDNA_DRIVER_MINOR 1
/*
* Bind the driver base on (vendor_id, device_id) pair and later use the
* (device_id, rev_id) pair as a key to select the devices. The devices with
@@ -164,6 +171,23 @@ static int amdxdna_drm_get_info_ioctl(struct drm_device *dev, void *data, struct
return ret;
}
static int amdxdna_drm_get_array_ioctl(struct drm_device *dev, void *data,
struct drm_file *filp)
{
struct amdxdna_client *client = filp->driver_priv;
struct amdxdna_dev *xdna = to_xdna_dev(dev);
struct amdxdna_drm_get_array *args = data;
if (!xdna->dev_info->ops->get_array)
return -EOPNOTSUPP;
if (args->pad || !args->num_element || !args->element_size)
return -EINVAL;
guard(mutex)(&xdna->dev_lock);
return xdna->dev_info->ops->get_array(client, args);
}
static int amdxdna_drm_set_state_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
{
struct amdxdna_client *client = filp->driver_priv;
@@ -195,6 +219,7 @@ static const struct drm_ioctl_desc amdxdna_drm_ioctls[] = {
DRM_IOCTL_DEF_DRV(AMDXDNA_EXEC_CMD, amdxdna_drm_submit_cmd_ioctl, 0),
/* AIE hardware */
DRM_IOCTL_DEF_DRV(AMDXDNA_GET_INFO, amdxdna_drm_get_info_ioctl, 0),
DRM_IOCTL_DEF_DRV(AMDXDNA_GET_ARRAY, amdxdna_drm_get_array_ioctl, 0),
DRM_IOCTL_DEF_DRV(AMDXDNA_SET_STATE, amdxdna_drm_set_state_ioctl, DRM_ROOT_ONLY),
};
@@ -218,6 +243,8 @@ const struct drm_driver amdxdna_drm_drv = {
.fops = &amdxdna_fops,
.name = "amdxdna_accel_driver",
.desc = "AMD XDNA DRM implementation",
.major = AMDXDNA_DRIVER_MAJOR,
.minor = AMDXDNA_DRIVER_MINOR,
.open = amdxdna_drm_open,
.postclose = amdxdna_drm_close,
.ioctls = amdxdna_drm_ioctls,

View File

@@ -58,6 +58,7 @@ struct amdxdna_dev_ops {
int (*cmd_submit)(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job, u64 *seq);
int (*get_aie_info)(struct amdxdna_client *client, struct amdxdna_drm_get_info *args);
int (*set_aie_state)(struct amdxdna_client *client, struct amdxdna_drm_set_state *args);
int (*get_array)(struct amdxdna_client *client, struct amdxdna_drm_get_array *args);
};
/*

View File

@@ -313,11 +313,23 @@ struct dma_buf *amdgpu_gem_prime_export(struct drm_gem_object *gobj,
{
struct amdgpu_bo *bo = gem_to_amdgpu_bo(gobj);
struct dma_buf *buf;
struct ttm_operation_ctx ctx = {
.interruptible = true,
.no_wait_gpu = true,
/* We opt to avoid OOM on system pages allocations */
.gfp_retry_mayfail = true,
.allow_res_evict = false,
};
int ret;
if (amdgpu_ttm_tt_get_usermm(bo->tbo.ttm) ||
bo->flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID)
return ERR_PTR(-EPERM);
ret = ttm_bo_setup_export(&bo->tbo, &ctx);
if (ret)
return ERR_PTR(ret);
buf = drm_gem_prime_export(gobj, flags);
if (!IS_ERR(buf))
buf->ops = &amdgpu_dmabuf_ops;

View File

@@ -31,6 +31,39 @@
#include "ast_drv.h"
#include "ast_post.h"
/*
* DRAM type
*/
static enum ast_dram_layout ast_2100_get_dram_layout_p2a(struct ast_device *ast)
{
u32 mcr_cfg;
enum ast_dram_layout dram_layout;
ast_write32(ast, 0xf004, 0x1e6e0000);
ast_write32(ast, 0xf000, 0x1);
mcr_cfg = ast_read32(ast, 0x10004);
switch (mcr_cfg & 0x0c) {
case 0:
case 4:
default:
dram_layout = AST_DRAM_512Mx16;
break;
case 8:
if (mcr_cfg & 0x40)
dram_layout = AST_DRAM_1Gx16;
else
dram_layout = AST_DRAM_512Mx32;
break;
case 0xc:
dram_layout = AST_DRAM_1Gx32;
break;
}
return dram_layout;
}
/*
* POST
*/
@@ -266,6 +299,7 @@ static void ast_post_chip_2100(struct ast_device *ast)
u8 j;
u32 data, temp, i;
const struct ast_dramstruct *dram_reg_info;
enum ast_dram_layout dram_layout = ast_2100_get_dram_layout_p2a(ast);
j = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff);
@@ -292,11 +326,17 @@ static void ast_post_chip_2100(struct ast_device *ast)
for (i = 0; i < 15; i++)
udelay(dram_reg_info->data);
} else if (AST_DRAMSTRUCT_IS(dram_reg_info, DRAM_TYPE)) {
data = dram_reg_info->data;
if (ast->dram_type == AST_DRAM_1Gx16)
switch (dram_layout) {
case AST_DRAM_1Gx16:
data = 0x00000d89;
else if (ast->dram_type == AST_DRAM_1Gx32)
break;
case AST_DRAM_1Gx32:
data = 0x00000c8d;
break;
default:
data = dram_reg_info->data;
break;
}
temp = ast_read32(ast, 0x12070);
temp &= 0xc;

View File

@@ -98,13 +98,15 @@ enum ast_config_mode {
ast_use_defaults
};
#define AST_DRAM_512Mx16 0
#define AST_DRAM_1Gx16 1
#define AST_DRAM_512Mx32 2
#define AST_DRAM_1Gx32 3
#define AST_DRAM_2Gx16 6
#define AST_DRAM_4Gx16 7
#define AST_DRAM_8Gx16 8
enum ast_dram_layout {
AST_DRAM_512Mx16 = 0,
AST_DRAM_1Gx16 = 1,
AST_DRAM_512Mx32 = 2,
AST_DRAM_1Gx32 = 3,
AST_DRAM_2Gx16 = 6,
AST_DRAM_4Gx16 = 7,
AST_DRAM_8Gx16 = 8,
};
/*
* Hardware cursor
@@ -172,10 +174,6 @@ struct ast_device {
enum ast_config_mode config_mode;
enum ast_chip chip;
uint32_t dram_bus_width;
uint32_t dram_type;
uint32_t mclk;
void __iomem *vram;
unsigned long vram_base;
unsigned long vram_size;

View File

@@ -210,126 +210,6 @@ static void ast_detect_tx_chip(struct ast_device *ast, bool need_post)
drm_info(dev, "Using %s\n", info_str[ast->tx_chip]);
}
static int ast_get_dram_info(struct ast_device *ast)
{
struct drm_device *dev = &ast->base;
struct device_node *np = dev->dev->of_node;
uint32_t mcr_cfg, mcr_scu_mpll, mcr_scu_strap;
uint32_t denum, num, div, ref_pll, dsel;
switch (ast->config_mode) {
case ast_use_dt:
/*
* If some properties are missing, use reasonable
* defaults for GEN5
*/
if (of_property_read_u32(np, "aspeed,mcr-configuration",
&mcr_cfg))
mcr_cfg = 0x00000577;
if (of_property_read_u32(np, "aspeed,mcr-scu-mpll",
&mcr_scu_mpll))
mcr_scu_mpll = 0x000050C0;
if (of_property_read_u32(np, "aspeed,mcr-scu-strap",
&mcr_scu_strap))
mcr_scu_strap = 0;
break;
case ast_use_p2a:
ast_write32(ast, 0xf004, 0x1e6e0000);
ast_write32(ast, 0xf000, 0x1);
mcr_cfg = ast_read32(ast, 0x10004);
mcr_scu_mpll = ast_read32(ast, 0x10120);
mcr_scu_strap = ast_read32(ast, 0x10170);
break;
case ast_use_defaults:
default:
ast->dram_bus_width = 16;
ast->dram_type = AST_DRAM_1Gx16;
if (IS_AST_GEN6(ast))
ast->mclk = 800;
else
ast->mclk = 396;
return 0;
}
if (mcr_cfg & 0x40)
ast->dram_bus_width = 16;
else
ast->dram_bus_width = 32;
if (IS_AST_GEN6(ast)) {
switch (mcr_cfg & 0x03) {
case 0:
ast->dram_type = AST_DRAM_1Gx16;
break;
default:
case 1:
ast->dram_type = AST_DRAM_2Gx16;
break;
case 2:
ast->dram_type = AST_DRAM_4Gx16;
break;
case 3:
ast->dram_type = AST_DRAM_8Gx16;
break;
}
} else if (IS_AST_GEN4(ast) || IS_AST_GEN5(ast)) {
switch (mcr_cfg & 0x03) {
case 0:
ast->dram_type = AST_DRAM_512Mx16;
break;
default:
case 1:
ast->dram_type = AST_DRAM_1Gx16;
break;
case 2:
ast->dram_type = AST_DRAM_2Gx16;
break;
case 3:
ast->dram_type = AST_DRAM_4Gx16;
break;
}
} else {
switch (mcr_cfg & 0x0c) {
case 0:
case 4:
ast->dram_type = AST_DRAM_512Mx16;
break;
case 8:
if (mcr_cfg & 0x40)
ast->dram_type = AST_DRAM_1Gx16;
else
ast->dram_type = AST_DRAM_512Mx32;
break;
case 0xc:
ast->dram_type = AST_DRAM_1Gx32;
break;
}
}
if (mcr_scu_strap & 0x2000)
ref_pll = 14318;
else
ref_pll = 12000;
denum = mcr_scu_mpll & 0x1f;
num = (mcr_scu_mpll & 0x3fe0) >> 5;
dsel = (mcr_scu_mpll & 0xc000) >> 14;
switch (dsel) {
case 3:
div = 0x4;
break;
case 2:
case 1:
div = 0x2;
break;
default:
div = 0x1;
break;
}
ast->mclk = ref_pll * (num + 2) / ((denum + 2) * (div * 1000));
return 0;
}
struct drm_device *ast_device_create(struct pci_dev *pdev,
const struct drm_driver *drv,
enum ast_chip chip,
@@ -352,12 +232,6 @@ struct drm_device *ast_device_create(struct pci_dev *pdev,
ast->regs = regs;
ast->ioregs = ioregs;
ret = ast_get_dram_info(ast);
if (ret)
return ERR_PTR(ret);
drm_info(dev, "dram MCLK=%u Mhz type=%d bus_width=%d\n",
ast->mclk, ast->dram_type, ast->dram_bus_width);
ast_detect_tx_chip(ast, need_post);
switch (ast->tx_chip) {
case AST_TX_ASTDP:

View File

@@ -12,6 +12,8 @@
#include <sound/soc.h>
#include <linux/of_graph.h>
#include <drm/display/drm_hdmi_state_helper.h>
#include "adv7511.h"
static void adv7511_calc_cts_n(unsigned int f_tmds, unsigned int fs,
@@ -155,17 +157,8 @@ int adv7511_hdmi_audio_prepare(struct drm_bridge *bridge,
regmap_update_bits(adv7511->regmap, ADV7511_REG_I2C_FREQ_ID_CFG,
ADV7511_I2C_FREQ_ID_CFG_RATE_MASK, rate << 4);
/* send current Audio infoframe values while updating */
regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
BIT(5), BIT(5));
regmap_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME(0), 0x1);
/* use Audio infoframe updated info */
regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
BIT(5), 0);
return 0;
return drm_atomic_helper_connector_hdmi_update_audio_infoframe(connector,
&hparms->cea);
}
int adv7511_hdmi_audio_startup(struct drm_bridge *bridge,
@@ -188,15 +181,9 @@ int adv7511_hdmi_audio_startup(struct drm_bridge *bridge,
/* not copyrighted */
regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CFG1,
BIT(5), BIT(5));
/* enable audio infoframes */
regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,
BIT(3), BIT(3));
/* AV mute disable */
regmap_update_bits(adv7511->regmap, ADV7511_REG_GC(0),
BIT(7) | BIT(6), BIT(7));
/* use Audio infoframe updated info */
regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
BIT(5), 0);
/* enable SPDIF receiver */
if (adv7511->audio_source == ADV7511_AUDIO_SOURCE_SPDIF)
@@ -214,4 +201,6 @@ void adv7511_hdmi_audio_shutdown(struct drm_bridge *bridge,
if (adv7511->audio_source == ADV7511_AUDIO_SOURCE_SPDIF)
regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,
BIT(7), 0);
drm_atomic_helper_connector_hdmi_clear_audio_infoframe(connector);
}

View File

@@ -893,6 +893,9 @@ static int adv7511_bridge_hdmi_clear_infoframe(struct drm_bridge *bridge,
struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
switch (type) {
case HDMI_INFOFRAME_TYPE_AUDIO:
adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_AUDIO_INFOFRAME);
break;
case HDMI_INFOFRAME_TYPE_AVI:
adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME);
break;
@@ -916,22 +919,48 @@ static int adv7511_bridge_hdmi_write_infoframe(struct drm_bridge *bridge,
{
struct adv7511 *adv7511 = bridge_to_adv7511(bridge);
adv7511_bridge_hdmi_clear_infoframe(bridge, type);
switch (type) {
case HDMI_INFOFRAME_TYPE_AUDIO:
/* send current Audio infoframe values while updating */
regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
BIT(5), BIT(5));
/* The Audio infoframe id is not configurable */
regmap_bulk_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME_VERSION,
buffer + 1, len - 1);
/* use Audio infoframe updated info */
regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
BIT(5), 0);
adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_AUDIO_INFOFRAME);
break;
case HDMI_INFOFRAME_TYPE_AVI:
/* send current AVI infoframe values while updating */
regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
BIT(6), BIT(6));
/* The AVI infoframe id is not configurable */
regmap_bulk_write(adv7511->regmap, ADV7511_REG_AVI_INFOFRAME_VERSION,
buffer + 1, len - 1);
regmap_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME_LENGTH, 0x2);
regmap_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME(1), 0x1);
/* use AVI infoframe updated info */
regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,
BIT(6), 0);
adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME);
break;
case HDMI_INFOFRAME_TYPE_SPD:
adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPD);
regmap_bulk_write(adv7511->regmap_packet, ADV7511_PACKET_SPD(0),
buffer, len);
adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_SPD);
break;
case HDMI_INFOFRAME_TYPE_VENDOR:
adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPARE1);
regmap_bulk_write(adv7511->regmap_packet, ADV7511_PACKET_SPARE1(0),
buffer, len);
adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_SPARE1);

View File

@@ -6,6 +6,7 @@ config DRM_CDNS_DSI
select DRM_PANEL_BRIDGE
select GENERIC_PHY
select GENERIC_PHY_MIPI_DPHY
select VIDEOMODE_HELPERS
depends on OF
help
Support Cadence DPI to DSI bridge. This is an internal

View File

@@ -146,6 +146,7 @@
#define HDMI_COLOR_DEPTH_24 FIELD_PREP(HDMI_COLOR_DEPTH, 4)
#define HDMI_REG_PKT_GENERAL_CTRL 0xc6
#define HDMI_REG_PKT_NULL_CTRL 0xc9
#define HDMI_REG_AVI_INFOFRM_CTRL 0xcd
#define ENABLE_PKT BIT(0)
#define REPEAT_PKT BIT(1)
@@ -154,6 +155,12 @@
* 3) HDMI register bank1: 0x130 ~ 0x1ff (HDMI packet registers)
*/
/* NULL packet registers */
/* Header Byte(HB): n = 0 ~ 2 */
#define HDMI_REG_PKT_HB(n) (0x138 + (n))
/* Packet Byte(PB): n = 0 ~ 27(HDMI_MAX_INFOFRAME_SIZE), n = 0 for checksum */
#define HDMI_REG_PKT_PB(n) (0x13b + (n))
/* AVI packet registers */
#define HDMI_REG_AVI_DB1 0x158
#define HDMI_REG_AVI_DB2 0x159
@@ -224,7 +231,9 @@ static bool it6263_hdmi_writeable_reg(struct device *dev, unsigned int reg)
case HDMI_REG_HDMI_MODE:
case HDMI_REG_GCP:
case HDMI_REG_PKT_GENERAL_CTRL:
case HDMI_REG_PKT_NULL_CTRL:
case HDMI_REG_AVI_INFOFRM_CTRL:
case HDMI_REG_PKT_HB(0) ... HDMI_REG_PKT_PB(HDMI_MAX_INFOFRAME_SIZE):
case HDMI_REG_AVI_DB1:
case HDMI_REG_AVI_DB2:
case HDMI_REG_AVI_DB3:
@@ -755,10 +764,16 @@ static int it6263_hdmi_clear_infoframe(struct drm_bridge *bridge,
{
struct it6263 *it = bridge_to_it6263(bridge);
if (type == HDMI_INFOFRAME_TYPE_AVI)
switch (type) {
case HDMI_INFOFRAME_TYPE_AVI:
regmap_write(it->hdmi_regmap, HDMI_REG_AVI_INFOFRM_CTRL, 0);
else
break;
case HDMI_INFOFRAME_TYPE_VENDOR:
regmap_write(it->hdmi_regmap, HDMI_REG_PKT_NULL_CTRL, 0);
break;
default:
dev_dbg(it->dev, "unsupported HDMI infoframe 0x%x\n", type);
}
return 0;
}
@@ -770,27 +785,36 @@ static int it6263_hdmi_write_infoframe(struct drm_bridge *bridge,
struct it6263 *it = bridge_to_it6263(bridge);
struct regmap *regmap = it->hdmi_regmap;
if (type != HDMI_INFOFRAME_TYPE_AVI) {
switch (type) {
case HDMI_INFOFRAME_TYPE_AVI:
/* write the first AVI infoframe data byte chunk(DB1-DB5) */
regmap_bulk_write(regmap, HDMI_REG_AVI_DB1,
&buffer[HDMI_INFOFRAME_HEADER_SIZE],
HDMI_AVI_DB_CHUNK1_SIZE);
/* write the second AVI infoframe data byte chunk(DB6-DB13) */
regmap_bulk_write(regmap, HDMI_REG_AVI_DB6,
&buffer[HDMI_INFOFRAME_HEADER_SIZE +
HDMI_AVI_DB_CHUNK1_SIZE],
HDMI_AVI_DB_CHUNK2_SIZE);
/* write checksum */
regmap_write(regmap, HDMI_REG_AVI_CSUM, buffer[3]);
regmap_write(regmap, HDMI_REG_AVI_INFOFRM_CTRL,
ENABLE_PKT | REPEAT_PKT);
break;
case HDMI_INFOFRAME_TYPE_VENDOR:
/* write header and payload */
regmap_bulk_write(regmap, HDMI_REG_PKT_HB(0), buffer, len);
regmap_write(regmap, HDMI_REG_PKT_NULL_CTRL,
ENABLE_PKT | REPEAT_PKT);
break;
default:
dev_dbg(it->dev, "unsupported HDMI infoframe 0x%x\n", type);
return 0;
}
/* write the first AVI infoframe data byte chunk(DB1-DB5) */
regmap_bulk_write(regmap, HDMI_REG_AVI_DB1,
&buffer[HDMI_INFOFRAME_HEADER_SIZE],
HDMI_AVI_DB_CHUNK1_SIZE);
/* write the second AVI infoframe data byte chunk(DB6-DB13) */
regmap_bulk_write(regmap, HDMI_REG_AVI_DB6,
&buffer[HDMI_INFOFRAME_HEADER_SIZE +
HDMI_AVI_DB_CHUNK1_SIZE],
HDMI_AVI_DB_CHUNK2_SIZE);
/* write checksum */
regmap_write(regmap, HDMI_REG_AVI_CSUM, buffer[3]);
regmap_write(regmap, HDMI_REG_AVI_INFOFRM_CTRL, ENABLE_PKT | REPEAT_PKT);
return 0;
}

View File

@@ -266,6 +266,11 @@ static const struct of_device_id simple_bridge_match[] = {
.data = &(const struct simple_bridge_info) {
.connector_type = DRM_MODE_CONNECTOR_HDMIA,
},
}, {
.compatible = "realtek,rtd2171",
.data = &(const struct simple_bridge_info) {
.connector_type = DRM_MODE_CONNECTOR_HDMIA,
},
}, {
.compatible = "ti,opa362",
.data = &(const struct simple_bridge_info) {

View File

@@ -776,8 +776,6 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
if (!connector->ycbcr_420_allowed)
supported_formats &= ~BIT(HDMI_COLORSPACE_YUV420);
bridge = bridge_connector->bridge_hdmi;
ret = drmm_connector_hdmi_init(drm, connector,
bridge_connector->bridge_hdmi->vendor,
bridge_connector->bridge_hdmi->product,

View File

@@ -18,6 +18,7 @@
#include <linux/gfp.h>
#include <linux/i2c.h>
#include <linux/kdev_t.h>
#include <linux/pci.h>
#include <linux/property.h>
#include <linux/slab.h>
@@ -30,6 +31,8 @@
#include <drm/drm_property.h>
#include <drm/drm_sysfs.h>
#include <asm/video.h>
#include "drm_internal.h"
#include "drm_crtc_internal.h"
@@ -508,6 +511,43 @@ void drm_sysfs_connector_property_event(struct drm_connector *connector,
}
EXPORT_SYMBOL(drm_sysfs_connector_property_event);
static ssize_t boot_display_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return sysfs_emit(buf, "1\n");
}
static DEVICE_ATTR_RO(boot_display);
static struct attribute *display_attrs[] = {
&dev_attr_boot_display.attr,
NULL
};
static umode_t boot_display_visible(struct kobject *kobj,
struct attribute *a, int n)
{
struct device *dev = kobj_to_dev(kobj)->parent;
if (dev_is_pci(dev)) {
struct pci_dev *pdev = to_pci_dev(dev);
if (video_is_primary_device(&pdev->dev))
return a->mode;
}
return 0;
}
static const struct attribute_group display_attr_group = {
.attrs = display_attrs,
.is_visible = boot_display_visible,
};
static const struct attribute_group *card_dev_groups[] = {
&display_attr_group,
NULL
};
struct device *drm_sysfs_minor_alloc(struct drm_minor *minor)
{
const char *minor_str;
@@ -531,6 +571,7 @@ struct device *drm_sysfs_minor_alloc(struct drm_minor *minor)
kdev->devt = MKDEV(DRM_MAJOR, minor->index);
kdev->class = drm_class;
kdev->groups = card_dev_groups;
kdev->type = &drm_sysfs_device_minor;
}

View File

@@ -120,7 +120,6 @@ static void psb_fbdev_fb_destroy(struct fb_info *info)
drm_fb_helper_fini(fb_helper);
drm_framebuffer_unregister_private(fb);
fb->obj[0] = NULL;
drm_framebuffer_cleanup(fb);
kfree(fb);
@@ -245,7 +244,6 @@ int psb_fbdev_driver_fbdev_probe(struct drm_fb_helper *fb_helper,
err_drm_framebuffer_unregister_private:
drm_framebuffer_unregister_private(fb);
fb->obj[0] = NULL;
drm_framebuffer_cleanup(fb);
kfree(fb);
err_drm_gem_object_put:

View File

@@ -108,9 +108,21 @@ struct dma_buf *nouveau_gem_prime_export(struct drm_gem_object *gobj,
int flags)
{
struct nouveau_bo *nvbo = nouveau_gem_object(gobj);
struct ttm_operation_ctx ctx = {
.interruptible = true,
.no_wait_gpu = true,
/* We opt to avoid OOM on system pages allocations */
.gfp_retry_mayfail = true,
.allow_res_evict = false,
};
int ret;
if (nvbo->no_share)
return ERR_PTR(-EPERM);
ret = ttm_bo_setup_export(&nvbo->bo, &ctx);
if (ret)
return ERR_PTR(ret);
return drm_gem_prime_export(gobj, flags);
}

View File

@@ -1843,6 +1843,13 @@ static const struct panel_delay delay_200_500_e50_d100 = {
.disable = 100,
};
static const struct panel_delay delay_80_500_e50_d50 = {
.hpd_absent = 80,
.unprepare = 500,
.enable = 50,
.disable = 50,
};
#define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _delay, _name) \
{ \
.ident = { \
@@ -1955,6 +1962,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a36, &delay_200_500_e200, "Unknown"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a3e, &delay_200_500_e80_d50, "NV116WHM-N49"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a6a, &delay_200_500_e80, "NV140WUM-N44"),
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', 0x0b09, &delay_200_500_e50_po2e200, "NV140FHM-NZ"),
@@ -1996,6 +2004,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('C', 'M', 'N', 0x124c, &delay_200_500_e80_d50, "N122JCA-ENK"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x142b, &delay_200_500_e80_d50, "N140HCA-EAC"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x142e, &delay_200_500_e80_d50, "N140BGA-EA4"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1441, &delay_200_500_e80_d50, "N140JCA-ELK"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x144f, &delay_200_500_e80_d50, "N140HGA-EA1"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1468, &delay_200_500_e80, "N140HGA-EA1"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x14a8, &delay_200_500_e80, "N140JCA-ELP"),
@@ -2011,10 +2020,12 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('C', 'S', 'W', 0x1100, &delay_200_500_e80_d50, "MNB601LS1-1"),
EDP_PANEL_ENTRY('C', 'S', 'W', 0x1103, &delay_200_500_e80_d50, "MNB601LS1-3"),
EDP_PANEL_ENTRY('C', 'S', 'W', 0x1104, &delay_200_500_e50_d100, "MNB601LS1-4"),
EDP_PANEL_ENTRY('C', 'S', 'W', 0x143f, &delay_200_500_e50, "MNE007QS3-6"),
EDP_PANEL_ENTRY('C', 'S', 'W', 0x1448, &delay_200_500_e50, "MNE007QS3-7"),
EDP_PANEL_ENTRY('C', 'S', 'W', 0x1457, &delay_80_500_e80_p2e200, "MNE007QS3-8"),
EDP_PANEL_ENTRY('C', 'S', 'W', 0x1462, &delay_200_500_e50, "MNE007QS5-2"),
EDP_PANEL_ENTRY('C', 'S', 'W', 0x1468, &delay_200_500_e50, "MNE007QB2-2"),
EDP_PANEL_ENTRY('C', 'S', 'W', 0x146e, &delay_80_500_e50_d50, "MNE007QB3-1"),
EDP_PANEL_ENTRY('E', 'T', 'C', 0x0000, &delay_50_500_e200_d200_po2e335, "LP079QX1-SP0V"),

View File

@@ -28,8 +28,6 @@ struct panel_lvds {
struct device *dev;
const char *label;
unsigned int width;
unsigned int height;
struct drm_display_mode dmode;
u32 bus_flags;
unsigned int bus_format;

View File

@@ -1013,7 +1013,7 @@ static int rcar_lvds_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops rcar_lvds_pm_ops = {
SET_RUNTIME_PM_OPS(rcar_lvds_runtime_suspend, rcar_lvds_runtime_resume, NULL)
RUNTIME_PM_OPS(rcar_lvds_runtime_suspend, rcar_lvds_runtime_resume, NULL)
};
static struct platform_driver rcar_lvds_platform_driver = {
@@ -1021,7 +1021,7 @@ static struct platform_driver rcar_lvds_platform_driver = {
.remove = rcar_lvds_remove,
.driver = {
.name = "rcar-lvds",
.pm = &rcar_lvds_pm_ops,
.pm = pm_ptr(&rcar_lvds_pm_ops),
.of_match_table = rcar_lvds_of_table,
},
};

View File

@@ -937,9 +937,234 @@ static int rcar_mipi_dsi_host_detach(struct mipi_dsi_host *host,
return 0;
}
static ssize_t rcar_mipi_dsi_host_tx_transfer(struct mipi_dsi_host *host,
const struct mipi_dsi_msg *msg,
bool is_rx_xfer)
{
const bool is_tx_long = mipi_dsi_packet_format_is_long(msg->type);
struct rcar_mipi_dsi *dsi = host_to_rcar_mipi_dsi(host);
struct mipi_dsi_packet packet;
u8 payload[16] = { 0 };
u32 status;
int ret;
ret = mipi_dsi_create_packet(&packet, msg);
if (ret)
return ret;
/* Configure LP or HS command transfer. */
rcar_mipi_dsi_write(dsi, TXCMSETR, (msg->flags & MIPI_DSI_MSG_USE_LPM) ?
TXCMSETR_SPDTYP : 0);
/* Register access mode for RX transfer. */
if (is_rx_xfer)
rcar_mipi_dsi_write(dsi, RXPSETR, 0);
/* Do not use IRQ, poll for completion, the completion is quick. */
rcar_mipi_dsi_write(dsi, TXCMIER, 0);
/*
* Send the header:
* header[0] = Virtual Channel + Data Type
* header[1] = Word Count LSB (LP) or first param (SP)
* header[2] = Word Count MSB (LP) or second param (SP)
*/
rcar_mipi_dsi_write(dsi, TXCMPHDR,
(is_tx_long ? TXCMPHDR_FMT : 0) |
TXCMPHDR_VC(msg->channel) |
TXCMPHDR_DT(msg->type) |
TXCMPHDR_DATA1(packet.header[2]) |
TXCMPHDR_DATA0(packet.header[1]));
if (is_tx_long) {
memcpy(payload, packet.payload,
min(msg->tx_len, sizeof(payload)));
rcar_mipi_dsi_write(dsi, TXCMPPD0R,
(payload[3] << 24) | (payload[2] << 16) |
(payload[1] << 8) | payload[0]);
rcar_mipi_dsi_write(dsi, TXCMPPD1R,
(payload[7] << 24) | (payload[6] << 16) |
(payload[5] << 8) | payload[4]);
rcar_mipi_dsi_write(dsi, TXCMPPD2R,
(payload[11] << 24) | (payload[10] << 16) |
(payload[9] << 8) | payload[8]);
rcar_mipi_dsi_write(dsi, TXCMPPD3R,
(payload[15] << 24) | (payload[14] << 16) |
(payload[13] << 8) | payload[12]);
}
/* Start the transfer, RX with BTA, TX without BTA. */
if (is_rx_xfer) {
rcar_mipi_dsi_write(dsi, TXCMCR, TXCMCR_BTAREQ);
/* Wait until the transmission, BTA, reception completed. */
ret = read_poll_timeout(rcar_mipi_dsi_read, status,
(status & RXPSR_BTAREQEND),
2000, 50000, false, dsi, RXPSR);
} else {
rcar_mipi_dsi_write(dsi, TXCMCR, TXCMCR_TXREQ);
/* Wait until the transmission completed. */
ret = read_poll_timeout(rcar_mipi_dsi_read, status,
(status & TXCMSR_TXREQEND),
2000, 50000, false, dsi, TXCMSR);
}
if (ret < 0) {
dev_err(dsi->dev, "Command transfer timeout (0x%08x)\n",
status);
return ret;
}
return packet.size;
}
static ssize_t rcar_mipi_dsi_host_rx_transfer(struct mipi_dsi_host *host,
const struct mipi_dsi_msg *msg)
{
struct rcar_mipi_dsi *dsi = host_to_rcar_mipi_dsi(host);
u8 *rx_buf = (u8 *)(msg->rx_buf);
u32 reg, data, status, wc;
int i, ret;
/* RX transfer received data validation and parsing starts here. */
reg = rcar_mipi_dsi_read(dsi, TOSR);
if (reg & TOSR_TATO) { /* Turn-Around TimeOut. */
/* Clear TATO Turn-Around TimeOut bit. */
rcar_mipi_dsi_write(dsi, TOSR, TOSR_TATO);
return -ETIMEDOUT;
}
reg = rcar_mipi_dsi_read(dsi, RXPSR);
if (msg->flags & MIPI_DSI_MSG_REQ_ACK) {
/* Transfer with zero-length RX. */
if (!(reg & RXPSR_RCVACK)) {
/* No ACK on RX response received. */
return -EINVAL;
}
} else {
/* Transfer with non-zero-length RX. */
if (!(reg & RXPSR_RCVRESP)) {
/* No packet header of RX response received. */
return -EINVAL;
}
if (reg & (RXPSR_CRCERR | RXPSR_WCERR | RXPSR_AXIERR | RXPSR_OVRERR)) {
/* Incorrect response payload. */
return -ENODATA;
}
data = rcar_mipi_dsi_read(dsi, RXPHDR);
if (data & RXPHDR_FMT) { /* Long Packet Response. */
/* Read Long Packet Response length from packet header. */
wc = data & 0xffff;
if (wc > msg->rx_len) {
dev_warn(dsi->dev,
"Long Packet Response longer than RX buffer (%d), limited to %zu Bytes\n",
wc, msg->rx_len);
wc = msg->rx_len;
}
if (wc > 16) {
dev_warn(dsi->dev,
"Long Packet Response too long (%d), limited to 16 Bytes\n",
wc);
wc = 16;
}
for (i = 0; i < msg->rx_len; i++) {
if (!(i % 4))
data = rcar_mipi_dsi_read(dsi, RXPPD0R + i);
rx_buf[i] = data & 0xff;
data >>= 8;
}
} else { /* Short Packet Response. */
if (msg->rx_len >= 1)
rx_buf[0] = data & 0xff;
if (msg->rx_len >= 2)
rx_buf[1] = (data >> 8) & 0xff;
if (msg->rx_len >= 3) {
dev_warn(dsi->dev,
"Expected Short Packet Response too long (%zu), limited to 2 Bytes\n",
msg->rx_len);
}
}
}
if (reg & RXPSR_RCVAKE) {
/* Acknowledge and Error report received. */
return -EFAULT;
}
/* Wait until the bus handover to host processor completed. */
ret = read_poll_timeout(rcar_mipi_dsi_read, status,
!(status & PPIDL0SR_DIR),
2000, 50000, false, dsi, PPIDL0SR);
if (ret < 0) {
dev_err(dsi->dev, "Command RX DIR timeout (0x%08x)\n", status);
return ret;
}
/* Wait until the data lane is in LP11 stop state. */
ret = read_poll_timeout(rcar_mipi_dsi_read, status,
status & PPIDL0SR_STPST,
2000, 50000, false, dsi, PPIDL0SR);
if (ret < 0) {
dev_err(dsi->dev, "Command RX STPST timeout (0x%08x)\n", status);
return ret;
}
return 0;
}
static ssize_t rcar_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
const struct mipi_dsi_msg *msg)
{
const bool is_rx_xfer = (msg->flags & MIPI_DSI_MSG_REQ_ACK) || msg->rx_len;
struct rcar_mipi_dsi *dsi = host_to_rcar_mipi_dsi(host);
int ret;
if (msg->tx_len > 16 || msg->rx_len > 16) {
/* ToDo: Implement Memory on AXI bus command mode. */
dev_warn(dsi->dev,
"Register-based command mode supports only up to 16 Bytes long payload\n");
return -EOPNOTSUPP;
}
ret = rcar_mipi_dsi_host_tx_transfer(host, msg, is_rx_xfer);
/* If TX transfer succeeded and this transfer has RX part. */
if (ret >= 0 && is_rx_xfer) {
ret = rcar_mipi_dsi_host_rx_transfer(host, msg);
if (ret)
return ret;
ret = msg->rx_len;
}
/*
* Wait a bit between commands, otherwise panels based on ILI9881C
* TCON may fail to correctly receive all commands sent to them.
* Until we can actually test with another DSI device, keep the
* delay here, but eventually this delay might have to be moved
* into the ILI9881C panel driver.
*/
usleep_range(1000, 2000);
/* Clear the completion interrupt. */
if (!msg->rx_len)
rcar_mipi_dsi_write(dsi, TXCMSR, TXCMSR_TXREQEND);
return ret;
}
static const struct mipi_dsi_host_ops rcar_mipi_dsi_host_ops = {
.attach = rcar_mipi_dsi_host_attach,
.detach = rcar_mipi_dsi_host_detach,
.transfer = rcar_mipi_dsi_host_transfer
};
/* -----------------------------------------------------------------------------

View File

@@ -15,6 +15,127 @@
#define TXSETR 0x100
#define TXSETR_LANECNT_MASK (0x3 << 0)
/*
* DSI Command Transfer Registers
*/
#define TXCMSETR 0x110
#define TXCMSETR_SPDTYP (1 << 8) /* 0:HS 1:LP */
#define TXCMSETR_LPPDACC (1 << 0)
#define TXCMCR 0x120
#define TXCMCR_BTATYP (1 << 2)
#define TXCMCR_BTAREQ (1 << 1)
#define TXCMCR_TXREQ (1 << 0)
#define TXCMSR 0x130
#define TXCMSR_CLSNERR (1 << 18)
#define TXCMSR_AXIERR (1 << 16)
#define TXCMSR_TXREQEND (1 << 0)
#define TXCMSCR 0x134
#define TXCMSCR_CLSNERR (1 << 18)
#define TXCMSCR_AXIERR (1 << 16)
#define TXCMSCR_TXREQEND (1 << 0)
#define TXCMIER 0x138
#define TXCMIER_CLSNERR (1 << 18)
#define TXCMIER_AXIERR (1 << 16)
#define TXCMIER_TXREQEND (1 << 0)
#define TXCMADDRSET0R 0x140
#define TXCMPHDR 0x150
#define TXCMPHDR_FMT (1 << 24) /* 0:SP 1:LP */
#define TXCMPHDR_VC(n) (((n) & 0x3) << 22)
#define TXCMPHDR_DT(n) (((n) & 0x3f) << 16)
#define TXCMPHDR_DATA1(n) (((n) & 0xff) << 8)
#define TXCMPHDR_DATA0(n) (((n) & 0xff) << 0)
#define TXCMPPD0R 0x160
#define TXCMPPD1R 0x164
#define TXCMPPD2R 0x168
#define TXCMPPD3R 0x16c
#define RXSETR 0x200
#define RXSETR_CRCEN (((n) & 0xf) << 24)
#define RXSETR_ECCEN (((n) & 0xf) << 16)
#define RXPSETR 0x210
#define RXPSETR_LPPDACC (1 << 0)
#define RXPSR 0x220
#define RXPSR_ECCERR1B (1 << 28)
#define RXPSR_UEXTRGERR (1 << 25)
#define RXPSR_RESPTOERR (1 << 24)
#define RXPSR_OVRERR (1 << 23)
#define RXPSR_AXIERR (1 << 22)
#define RXPSR_CRCERR (1 << 21)
#define RXPSR_WCERR (1 << 20)
#define RXPSR_UEXDTERR (1 << 19)
#define RXPSR_UEXPKTERR (1 << 18)
#define RXPSR_ECCERR (1 << 17)
#define RXPSR_MLFERR (1 << 16)
#define RXPSR_RCVACK (1 << 14)
#define RXPSR_RCVEOT (1 << 10)
#define RXPSR_RCVAKE (1 << 9)
#define RXPSR_RCVRESP (1 << 8)
#define RXPSR_BTAREQEND (1 << 0)
#define RXPSCR 0x224
#define RXPSCR_ECCERR1B (1 << 28)
#define RXPSCR_UEXTRGERR (1 << 25)
#define RXPSCR_RESPTOERR (1 << 24)
#define RXPSCR_OVRERR (1 << 23)
#define RXPSCR_AXIERR (1 << 22)
#define RXPSCR_CRCERR (1 << 21)
#define RXPSCR_WCERR (1 << 20)
#define RXPSCR_UEXDTERR (1 << 19)
#define RXPSCR_UEXPKTERR (1 << 18)
#define RXPSCR_ECCERR (1 << 17)
#define RXPSCR_MLFERR (1 << 16)
#define RXPSCR_RCVACK (1 << 14)
#define RXPSCR_RCVEOT (1 << 10)
#define RXPSCR_RCVAKE (1 << 9)
#define RXPSCR_RCVRESP (1 << 8)
#define RXPSCR_BTAREQEND (1 << 0)
#define RXPIER 0x228
#define RXPIER_ECCERR1B (1 << 28)
#define RXPIER_UEXTRGERR (1 << 25)
#define RXPIER_RESPTOERR (1 << 24)
#define RXPIER_OVRERR (1 << 23)
#define RXPIER_AXIERR (1 << 22)
#define RXPIER_CRCERR (1 << 21)
#define RXPIER_WCERR (1 << 20)
#define RXPIER_UEXDTERR (1 << 19)
#define RXPIER_UEXPKTERR (1 << 18)
#define RXPIER_ECCERR (1 << 17)
#define RXPIER_MLFERR (1 << 16)
#define RXPIER_RCVACK (1 << 14)
#define RXPIER_RCVEOT (1 << 10)
#define RXPIER_RCVAKE (1 << 9)
#define RXPIER_RCVRESP (1 << 8)
#define RXPIER_BTAREQEND (1 << 0)
#define RXPADDRSET0R 0x230
#define RXPSIZESETR 0x238
#define RXPSIZESETR_SIZE(n) (((n) & 0xf) << 3)
#define RXPHDR 0x240
#define RXPHDR_FMT (1 << 24) /* 0:SP 1:LP */
#define RXPHDR_VC(n) (((n) & 0x3) << 22)
#define RXPHDR_DT(n) (((n) & 0x3f) << 16)
#define RXPHDR_DATA1(n) (((n) & 0xff) << 8)
#define RXPHDR_DATA0(n) (((n) & 0xff) << 0)
#define RXPPD0R 0x250
#define RXPPD1R 0x254
#define RXPPD2R 0x258
#define RXPPD3R 0x25c
#define AKEPR 0x300
#define AKEPR_VC(n) (((n) & 0x3) << 22)
#define AKEPR_DT(n) (((n) & 0x3f) << 16)
#define AKEPR_ERRRPT(n) (((n) & 0xffff) << 0)
#define RXRESPTOSETR 0x400
#define TACR 0x500
#define TASR 0x510
#define TASCR 0x514
#define TAIER 0x518
#define TOSR 0x610
#define TOSR_TATO (1 << 2)
#define TOSR_LRXHTO (1 << 1)
#define TOSR_HRXTO (1 << 0)
#define TOSCR 0x614
#define TOSCR_TATO (1 << 2)
#define TOSCR_LRXHTO (1 << 1)
#define TOSCR_HRXTO (1 << 0)
/*
* Video Mode Register
*/
@@ -100,6 +221,10 @@
#define PPICLSCR_HSTOLP (1 << 27)
#define PPICLSCR_TOHS (1 << 26)
#define PPIDL0SR 0x740
#define PPIDL0SR_DIR (1 << 10)
#define PPIDL0SR_STPST (1 << 6)
#define PPIDLSR 0x760
#define PPIDLSR_STPST (0xf << 0)

View File

@@ -744,7 +744,7 @@ static bool sti_hqvdp_check_hw_scaling(struct sti_hqvdp *hqvdp,
inv_zy = DIV_ROUND_UP(src_h, dst_h);
return (inv_zy <= lfw) ? true : false;
return inv_zy <= lfw;
}
/**

View File

@@ -82,6 +82,21 @@ config DRM_PANEL_MIPI_DBI
https://github.com/notro/panel-mipi-dbi/wiki.
To compile this driver as a module, choose M here.
config DRM_PIXPAPER
tristate "DRM support for PIXPAPER display panels"
depends on DRM && SPI
select DRM_CLIENT_SELECTION
select DRM_GEM_DMA_HELPER
select DRM_KMS_HELPER
help
DRM driver for the Mayqueen Pixpaper e-ink display panel.
This driver supports small e-paper displays connected over SPI,
with a resolution of 122x250 and XRGB8888 framebuffer format.
It is intended for low-power embedded applications.
If M is selected, the module will be built as pixpaper.ko.
config TINYDRM_HX8357D
tristate "DRM support for HX8357D display panels"
depends on DRM && SPI

View File

@@ -6,6 +6,7 @@ obj-$(CONFIG_DRM_BOCHS) += bochs.o
obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus-qemu.o
obj-$(CONFIG_DRM_GM12U320) += gm12u320.o
obj-$(CONFIG_DRM_PANEL_MIPI_DBI) += panel-mipi-dbi.o
obj-$(CONFIG_DRM_PIXPAPER) += pixpaper.o
obj-$(CONFIG_TINYDRM_HX8357D) += hx8357d.o
obj-$(CONFIG_TINYDRM_ILI9163) += ili9163.o
obj-$(CONFIG_TINYDRM_ILI9225) += ili9225.o

View File

@@ -252,7 +252,7 @@ static int bochs_hw_init(struct bochs_device *bochs)
}
bochs->ioports = 1;
} else {
dev_err(dev->dev, "I/O ports are not supported\n");
drm_err(dev, "I/O ports are not supported\n");
return -EIO;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1283,3 +1283,18 @@ int ttm_bo_populate(struct ttm_buffer_object *bo,
return 0;
}
EXPORT_SYMBOL(ttm_bo_populate);
int ttm_bo_setup_export(struct ttm_buffer_object *bo,
struct ttm_operation_ctx *ctx)
{
int ret;
ret = ttm_bo_reserve(bo, false, false, NULL);
if (ret != 0)
return ret;
ret = ttm_bo_populate(bo, ctx);
ttm_bo_unreserve(bo);
return ret;
}
EXPORT_SYMBOL(ttm_bo_setup_export);

View File

@@ -200,6 +200,7 @@ static void vkms_config_test_get_planes(struct kunit *test)
KUNIT_ASSERT_EQ(test, n_planes, 0);
plane_cfg1 = vkms_config_create_plane(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_cfg1);
vkms_config_for_each_plane(config, plane_cfg) {
n_planes++;
if (plane_cfg != plane_cfg1)
@@ -209,6 +210,7 @@ static void vkms_config_test_get_planes(struct kunit *test)
n_planes = 0;
plane_cfg2 = vkms_config_create_plane(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_cfg2);
vkms_config_for_each_plane(config, plane_cfg) {
n_planes++;
if (plane_cfg != plane_cfg1 && plane_cfg != plane_cfg2)
@@ -242,6 +244,7 @@ static void vkms_config_test_get_crtcs(struct kunit *test)
KUNIT_FAIL(test, "Unexpected CRTC");
crtc_cfg1 = vkms_config_create_crtc(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_cfg1);
KUNIT_ASSERT_EQ(test, vkms_config_get_num_crtcs(config), 1);
vkms_config_for_each_crtc(config, crtc_cfg) {
if (crtc_cfg != crtc_cfg1)
@@ -249,6 +252,7 @@ static void vkms_config_test_get_crtcs(struct kunit *test)
}
crtc_cfg2 = vkms_config_create_crtc(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_cfg2);
KUNIT_ASSERT_EQ(test, vkms_config_get_num_crtcs(config), 2);
vkms_config_for_each_crtc(config, crtc_cfg) {
if (crtc_cfg != crtc_cfg1 && crtc_cfg != crtc_cfg2)
@@ -280,6 +284,7 @@ static void vkms_config_test_get_encoders(struct kunit *test)
KUNIT_ASSERT_EQ(test, n_encoders, 0);
encoder_cfg1 = vkms_config_create_encoder(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder_cfg1);
vkms_config_for_each_encoder(config, encoder_cfg) {
n_encoders++;
if (encoder_cfg != encoder_cfg1)
@@ -289,6 +294,7 @@ static void vkms_config_test_get_encoders(struct kunit *test)
n_encoders = 0;
encoder_cfg2 = vkms_config_create_encoder(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder_cfg2);
vkms_config_for_each_encoder(config, encoder_cfg) {
n_encoders++;
if (encoder_cfg != encoder_cfg1 && encoder_cfg != encoder_cfg2)
@@ -324,6 +330,7 @@ static void vkms_config_test_get_connectors(struct kunit *test)
KUNIT_ASSERT_EQ(test, n_connectors, 0);
connector_cfg1 = vkms_config_create_connector(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector_cfg1);
vkms_config_for_each_connector(config, connector_cfg) {
n_connectors++;
if (connector_cfg != connector_cfg1)
@@ -333,6 +340,7 @@ static void vkms_config_test_get_connectors(struct kunit *test)
n_connectors = 0;
connector_cfg2 = vkms_config_create_connector(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector_cfg2);
vkms_config_for_each_connector(config, connector_cfg) {
n_connectors++;
if (connector_cfg != connector_cfg1 &&
@@ -370,7 +378,7 @@ static void vkms_config_test_invalid_plane_number(struct kunit *test)
/* Invalid: Too many planes */
for (n = 0; n <= 32; n++)
vkms_config_create_plane(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vkms_config_create_plane(config));
KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config));
@@ -395,6 +403,7 @@ static void vkms_config_test_valid_plane_type(struct kunit *test)
/* Invalid: No primary plane */
plane_cfg = vkms_config_create_plane(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_cfg);
vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_OVERLAY);
err = vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg);
KUNIT_EXPECT_EQ(test, err, 0);
@@ -402,11 +411,13 @@ static void vkms_config_test_valid_plane_type(struct kunit *test)
/* Invalid: Multiple primary planes */
plane_cfg = vkms_config_create_plane(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_cfg);
vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_PRIMARY);
err = vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg);
KUNIT_EXPECT_EQ(test, err, 0);
plane_cfg = vkms_config_create_plane(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_cfg);
vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_PRIMARY);
err = vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg);
KUNIT_EXPECT_EQ(test, err, 0);
@@ -419,11 +430,13 @@ static void vkms_config_test_valid_plane_type(struct kunit *test)
/* Invalid: Multiple cursor planes */
plane_cfg = vkms_config_create_plane(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_cfg);
vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_CURSOR);
err = vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg);
KUNIT_EXPECT_EQ(test, err, 0);
plane_cfg = vkms_config_create_plane(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_cfg);
vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_CURSOR);
err = vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg);
KUNIT_EXPECT_EQ(test, err, 0);
@@ -437,12 +450,16 @@ static void vkms_config_test_valid_plane_type(struct kunit *test)
/* Invalid: Second CRTC without primary plane */
crtc_cfg = vkms_config_create_crtc(config);
encoder_cfg = vkms_config_create_encoder(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_cfg);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder_cfg);
err = vkms_config_encoder_attach_crtc(encoder_cfg, crtc_cfg);
KUNIT_EXPECT_EQ(test, err, 0);
KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config));
/* Valid: Second CRTC with a primary plane */
plane_cfg = vkms_config_create_plane(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_cfg);
vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_PRIMARY);
err = vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg);
KUNIT_EXPECT_EQ(test, err, 0);
@@ -486,7 +503,7 @@ static void vkms_config_test_invalid_crtc_number(struct kunit *test)
/* Invalid: Too many CRTCs */
for (n = 0; n <= 32; n++)
vkms_config_create_crtc(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vkms_config_create_crtc(config));
KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config));
@@ -509,7 +526,7 @@ static void vkms_config_test_invalid_encoder_number(struct kunit *test)
/* Invalid: Too many encoders */
for (n = 0; n <= 32; n++)
vkms_config_create_encoder(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vkms_config_create_encoder(config));
KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config));
@@ -531,12 +548,15 @@ static void vkms_config_test_valid_encoder_possible_crtcs(struct kunit *test)
/* Invalid: Encoder without a possible CRTC */
encoder_cfg = vkms_config_create_encoder(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder_cfg);
KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config));
/* Valid: Second CRTC with shared encoder */
crtc_cfg2 = vkms_config_create_crtc(config);
plane_cfg = vkms_config_create_plane(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_cfg2);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_cfg);
vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_PRIMARY);
err = vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg2);
KUNIT_EXPECT_EQ(test, err, 0);
@@ -577,7 +597,7 @@ static void vkms_config_test_invalid_connector_number(struct kunit *test)
/* Invalid: Too many connectors */
for (n = 0; n <= 32; n++)
connector_cfg = vkms_config_create_connector(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vkms_config_create_connector(config));
KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config));
@@ -669,13 +689,19 @@ static void vkms_config_test_plane_attach_crtc(struct kunit *test)
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
overlay_cfg = vkms_config_create_plane(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, overlay_cfg);
vkms_config_plane_set_type(overlay_cfg, DRM_PLANE_TYPE_OVERLAY);
primary_cfg = vkms_config_create_plane(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, primary_cfg);
vkms_config_plane_set_type(primary_cfg, DRM_PLANE_TYPE_PRIMARY);
cursor_cfg = vkms_config_create_plane(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cursor_cfg);
vkms_config_plane_set_type(cursor_cfg, DRM_PLANE_TYPE_CURSOR);
crtc_cfg = vkms_config_create_crtc(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_cfg);
/* No primary or cursor planes */
KUNIT_EXPECT_NULL(test, vkms_config_crtc_primary_plane(config, crtc_cfg));
@@ -735,6 +761,11 @@ static void vkms_config_test_plane_get_possible_crtcs(struct kunit *test)
crtc_cfg1 = vkms_config_create_crtc(config);
crtc_cfg2 = vkms_config_create_crtc(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_cfg1);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_cfg2);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_cfg1);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_cfg2);
/* No possible CRTCs */
vkms_config_plane_for_each_possible_crtc(plane_cfg1, idx, possible_crtc)
KUNIT_FAIL(test, "Unexpected possible CRTC");
@@ -799,6 +830,11 @@ static void vkms_config_test_encoder_get_possible_crtcs(struct kunit *test)
crtc_cfg1 = vkms_config_create_crtc(config);
crtc_cfg2 = vkms_config_create_crtc(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder_cfg1);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder_cfg2);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_cfg1);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_cfg2);
/* No possible CRTCs */
vkms_config_encoder_for_each_possible_crtc(encoder_cfg1, idx, possible_crtc)
KUNIT_FAIL(test, "Unexpected possible CRTC");
@@ -863,6 +899,11 @@ static void vkms_config_test_connector_get_possible_encoders(struct kunit *test)
encoder_cfg1 = vkms_config_create_encoder(config);
encoder_cfg2 = vkms_config_create_encoder(config);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector_cfg1);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector_cfg2);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder_cfg1);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder_cfg2);
/* No possible encoders */
vkms_config_connector_for_each_possible_encoder(connector_cfg1, idx,
possible_encoder)

View File

@@ -14,20 +14,20 @@
MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
/**
* struct pixel_yuv_u8 - Internal representation of a pixel color.
* @y: Luma value, stored in 8 bits, without padding, using
* struct pixel_yuv_u16 - Internal representation of a pixel color.
* @y: Luma value, stored in 16 bits, without padding, using
* machine endianness
* @u: Blue difference chroma value, stored in 8 bits, without padding, using
* @u: Blue difference chroma value, stored in 16 bits, without padding, using
* machine endianness
* @v: Red difference chroma value, stored in 8 bits, without padding, using
* @v: Red difference chroma value, stored in 16 bits, without padding, using
* machine endianness
*/
struct pixel_yuv_u8 {
u8 y, u, v;
struct pixel_yuv_u16 {
u16 y, u, v;
};
/*
* struct yuv_u8_to_argb_u16_case - Reference values to test the color
* struct yuv_u16_to_argb_u16_case - Reference values to test the color
* conversions in VKMS between YUV to ARGB
*
* @encoding: Encoding used to convert RGB to YUV
@@ -39,13 +39,13 @@ struct pixel_yuv_u8 {
* @format_pair.yuv: Same color as @format_pair.rgb, but converted to
* YUV using @encoding and @range.
*/
struct yuv_u8_to_argb_u16_case {
struct yuv_u16_to_argb_u16_case {
enum drm_color_encoding encoding;
enum drm_color_range range;
size_t n_colors;
struct format_pair {
char *name;
struct pixel_yuv_u8 yuv;
struct pixel_yuv_u16 yuv;
struct pixel_argb_u16 argb;
} colors[TEST_BUFF_SIZE];
};
@@ -57,14 +57,14 @@ struct yuv_u8_to_argb_u16_case {
* For more information got to the docs:
* https://colour.readthedocs.io/en/master/generated/colour.RGB_to_YCbCr.html
*/
static struct yuv_u8_to_argb_u16_case yuv_u8_to_argb_u16_cases[] = {
static struct yuv_u16_to_argb_u16_case yuv_u16_to_argb_u16_cases[] = {
/*
* colour.RGB_to_YCbCr(<rgb color in 16 bit form>,
* K=colour.WEIGHTS_YCBCR["ITU-R BT.601"],
* in_bits = 16,
* in_legal = False,
* in_int = True,
* out_bits = 8,
* out_bits = 16,
* out_legal = False,
* out_int = True)
*
@@ -76,13 +76,13 @@ static struct yuv_u8_to_argb_u16_case yuv_u8_to_argb_u16_cases[] = {
.range = DRM_COLOR_YCBCR_FULL_RANGE,
.n_colors = 6,
.colors = {
{ "white", { 0xff, 0x80, 0x80 }, { 0xffff, 0xffff, 0xffff, 0xffff }},
{ "gray", { 0x80, 0x80, 0x80 }, { 0xffff, 0x8080, 0x8080, 0x8080 }},
{ "black", { 0x00, 0x80, 0x80 }, { 0xffff, 0x0000, 0x0000, 0x0000 }},
{ "red", { 0x4c, 0x55, 0xff }, { 0xffff, 0xffff, 0x0000, 0x0000 }},
{ "green", { 0x96, 0x2c, 0x15 }, { 0xffff, 0x0000, 0xffff, 0x0000 }},
{ "blue", { 0x1d, 0xff, 0x6b }, { 0xffff, 0x0000, 0x0000, 0xffff }},
},
{ "white", { 0xffff, 0x8000, 0x8000 }, { 0xffff, 0xffff, 0xffff, 0xffff }},
{ "gray", { 0x8080, 0x8000, 0x8000 }, { 0xffff, 0x8080, 0x8080, 0x8080 }},
{ "black", { 0x0000, 0x8000, 0x8000 }, { 0xffff, 0x0000, 0x0000, 0x0000 }},
{ "red", { 0x4c8b, 0x54ce, 0xffff }, { 0xffff, 0xffff, 0x0000, 0x0000 }},
{ "green", { 0x9645, 0x2b33, 0x14d1 }, { 0xffff, 0x0000, 0xffff, 0x0000 }},
{ "blue", { 0x1d2f, 0xffff, 0x6b2f }, { 0xffff, 0x0000, 0x0000, 0xffff }},
}
},
/*
* colour.RGB_to_YCbCr(<rgb color in 16 bit form>,
@@ -90,7 +90,7 @@ static struct yuv_u8_to_argb_u16_case yuv_u8_to_argb_u16_cases[] = {
* in_bits = 16,
* in_legal = False,
* in_int = True,
* out_bits = 8,
* out_bits = 16,
* out_legal = True,
* out_int = True)
* Tests cases for color conversion generated by converting RGB
@@ -101,13 +101,13 @@ static struct yuv_u8_to_argb_u16_case yuv_u8_to_argb_u16_cases[] = {
.range = DRM_COLOR_YCBCR_LIMITED_RANGE,
.n_colors = 6,
.colors = {
{ "white", { 0xeb, 0x80, 0x80 }, { 0xffff, 0xffff, 0xffff, 0xffff }},
{ "gray", { 0x7e, 0x80, 0x80 }, { 0xffff, 0x8080, 0x8080, 0x8080 }},
{ "black", { 0x10, 0x80, 0x80 }, { 0xffff, 0x0000, 0x0000, 0x0000 }},
{ "red", { 0x51, 0x5a, 0xf0 }, { 0xffff, 0xffff, 0x0000, 0x0000 }},
{ "green", { 0x91, 0x36, 0x22 }, { 0xffff, 0x0000, 0xffff, 0x0000 }},
{ "blue", { 0x29, 0xf0, 0x6e }, { 0xffff, 0x0000, 0x0000, 0xffff }},
},
{ "white", { 0xeb00, 0x8000, 0x8000 }, { 0xffff, 0xffff, 0xffff, 0xffff }},
{ "gray", { 0x7dee, 0x8000, 0x8000 }, { 0xffff, 0x8080, 0x8080, 0x8080 }},
{ "black", { 0x1000, 0x8000, 0x8000 }, { 0xffff, 0x0000, 0x0000, 0x0000 }},
{ "red", { 0x517b, 0x5a34, 0xf000 }, { 0xffff, 0xffff, 0x0000, 0x0000 }},
{ "green", { 0x908e, 0x35cc, 0x2237 }, { 0xffff, 0x0000, 0xffff, 0x0000 }},
{ "blue", { 0x28f7, 0xf000, 0x6dc9 }, { 0xffff, 0x0000, 0x0000, 0xffff }},
}
},
/*
* colour.RGB_to_YCbCr(<rgb color in 16 bit form>,
@@ -115,7 +115,7 @@ static struct yuv_u8_to_argb_u16_case yuv_u8_to_argb_u16_cases[] = {
* in_bits = 16,
* in_legal = False,
* in_int = True,
* out_bits = 8,
* out_bits = 16,
* out_legal = False,
* out_int = True)
* Tests cases for color conversion generated by converting RGB
@@ -126,21 +126,21 @@ static struct yuv_u8_to_argb_u16_case yuv_u8_to_argb_u16_cases[] = {
.range = DRM_COLOR_YCBCR_FULL_RANGE,
.n_colors = 6,
.colors = {
{ "white", { 0xff, 0x80, 0x80 }, { 0xffff, 0xffff, 0xffff, 0xffff }},
{ "gray", { 0x80, 0x80, 0x80 }, { 0xffff, 0x8080, 0x8080, 0x8080 }},
{ "black", { 0x00, 0x80, 0x80 }, { 0xffff, 0x0000, 0x0000, 0x0000 }},
{ "red", { 0x36, 0x63, 0xff }, { 0xffff, 0xffff, 0x0000, 0x0000 }},
{ "green", { 0xb6, 0x1e, 0x0c }, { 0xffff, 0x0000, 0xffff, 0x0000 }},
{ "blue", { 0x12, 0xff, 0x74 }, { 0xffff, 0x0000, 0x0000, 0xffff }},
},
{ "white", { 0xffff, 0x8000, 0x8000 }, { 0xffff, 0xffff, 0xffff, 0xffff }},
{ "gray", { 0x8080, 0x8000, 0x8000 }, { 0xffff, 0x8080, 0x8080, 0x8080 }},
{ "black", { 0x0000, 0x8000, 0x8000 }, { 0xffff, 0x0000, 0x0000, 0x0000 }},
{ "red", { 0x366d, 0x62ac, 0xffff }, { 0xffff, 0xffff, 0x0000, 0x0000 }},
{ "green", { 0xb717, 0x1d55, 0x0bbd }, { 0xffff, 0x0000, 0xffff, 0x0000 }},
{ "blue", { 0x127c, 0xffff, 0x7443 }, { 0xffff, 0x0000, 0x0000, 0xffff }},
}
},
/*
* colour.RGB_to_YCbCr(<rgb color in 16 bit form>,
* K=colour.WEIGHTS_YCBCR["ITU-R BT.709"],
* in_bits = 16,
* int_legal = False,
* in_legal = False,
* in_int = True,
* out_bits = 8,
* out_bits = 16,
* out_legal = True,
* out_int = True)
* Tests cases for color conversion generated by converting RGB
@@ -151,13 +151,13 @@ static struct yuv_u8_to_argb_u16_case yuv_u8_to_argb_u16_cases[] = {
.range = DRM_COLOR_YCBCR_LIMITED_RANGE,
.n_colors = 6,
.colors = {
{ "white", { 0xeb, 0x80, 0x80 }, { 0xffff, 0xffff, 0xffff, 0xffff }},
{ "gray", { 0x7e, 0x80, 0x80 }, { 0xffff, 0x8080, 0x8080, 0x8080 }},
{ "black", { 0x10, 0x80, 0x80 }, { 0xffff, 0x0000, 0x0000, 0x0000 }},
{ "red", { 0x3f, 0x66, 0xf0 }, { 0xffff, 0xffff, 0x0000, 0x0000 }},
{ "green", { 0xad, 0x2a, 0x1a }, { 0xffff, 0x0000, 0xffff, 0x0000 }},
{ "blue", { 0x20, 0xf0, 0x76 }, { 0xffff, 0x0000, 0x0000, 0xffff }},
},
{ "white", { 0xeb00, 0x8000, 0x8000 }, { 0xffff, 0xffff, 0xffff, 0xffff }},
{ "gray", { 0x7dee, 0x8000, 0x8000 }, { 0xffff, 0x8080, 0x8080, 0x8080 }},
{ "black", { 0x1000, 0x8000, 0x8000 }, { 0xffff, 0x0000, 0x0000, 0x0000 }},
{ "red", { 0x3e8f, 0x6656, 0xf000 }, { 0xffff, 0xffff, 0x0000, 0x0000 }},
{ "green", { 0xaca1, 0x29aa, 0x1a45 }, { 0xffff, 0x0000, 0xffff, 0x0000 }},
{ "blue", { 0x1fd0, 0xf000, 0x75bb }, { 0xffff, 0x0000, 0x0000, 0xffff }},
}
},
/*
* colour.RGB_to_YCbCr(<rgb color in 16 bit form>,
@@ -165,7 +165,7 @@ static struct yuv_u8_to_argb_u16_case yuv_u8_to_argb_u16_cases[] = {
* in_bits = 16,
* in_legal = False,
* in_int = True,
* out_bits = 8,
* out_bits = 16,
* out_legal = False,
* out_int = True)
* Tests cases for color conversion generated by converting RGB
@@ -176,13 +176,13 @@ static struct yuv_u8_to_argb_u16_case yuv_u8_to_argb_u16_cases[] = {
.range = DRM_COLOR_YCBCR_FULL_RANGE,
.n_colors = 6,
.colors = {
{ "white", { 0xff, 0x80, 0x80 }, { 0xffff, 0xffff, 0xffff, 0xffff }},
{ "gray", { 0x80, 0x80, 0x80 }, { 0xffff, 0x8080, 0x8080, 0x8080 }},
{ "black", { 0x00, 0x80, 0x80 }, { 0xffff, 0x0000, 0x0000, 0x0000 }},
{ "red", { 0x43, 0x5c, 0xff }, { 0xffff, 0xffff, 0x0000, 0x0000 }},
{ "green", { 0xad, 0x24, 0x0b }, { 0xffff, 0x0000, 0xffff, 0x0000 }},
{ "blue", { 0x0f, 0xff, 0x76 }, { 0xffff, 0x0000, 0x0000, 0xffff }},
},
{ "white", { 0xffff, 0x8000, 0x8000 }, { 0xffff, 0xffff, 0xffff, 0xffff }},
{ "gray", { 0x8080, 0x8000, 0x8000 }, { 0xffff, 0x8080, 0x8080, 0x8080 }},
{ "black", { 0x0000, 0x8000, 0x8000 }, { 0xffff, 0x0000, 0x0000, 0x0000 }},
{ "red", { 0x4340, 0x5c41, 0xffff }, { 0xffff, 0xffff, 0x0000, 0x0000 }},
{ "green", { 0xad91, 0x23bf, 0x0a4c }, { 0xffff, 0x0000, 0xffff, 0x0000 }},
{ "blue", { 0x0f2e, 0xffff, 0x75b5 }, { 0xffff, 0x0000, 0x0000, 0xffff }},
}
},
/*
* colour.RGB_to_YCbCr(<rgb color in 16 bit form>,
@@ -190,7 +190,7 @@ static struct yuv_u8_to_argb_u16_case yuv_u8_to_argb_u16_cases[] = {
* in_bits = 16,
* in_legal = False,
* in_int = True,
* out_bits = 8,
* out_bits = 16,
* out_legal = True,
* out_int = True)
* Tests cases for color conversion generated by converting RGB
@@ -201,32 +201,30 @@ static struct yuv_u8_to_argb_u16_case yuv_u8_to_argb_u16_cases[] = {
.range = DRM_COLOR_YCBCR_LIMITED_RANGE,
.n_colors = 6,
.colors = {
{ "white", { 0xeb, 0x80, 0x80 }, { 0xffff, 0xffff, 0xffff, 0xffff }},
{ "gray", { 0x7e, 0x80, 0x80 }, { 0xffff, 0x8080, 0x8080, 0x8080 }},
{ "black", { 0x10, 0x80, 0x80 }, { 0xffff, 0x0000, 0x0000, 0x0000 }},
{ "red", { 0x4a, 0x61, 0xf0 }, { 0xffff, 0xffff, 0x0000, 0x0000 }},
{ "green", { 0xa4, 0x2f, 0x19 }, { 0xffff, 0x0000, 0xffff, 0x0000 }},
{ "blue", { 0x1d, 0xf0, 0x77 }, { 0xffff, 0x0000, 0x0000, 0xffff }},
},
{ "white", { 0xeb00, 0x8000, 0x8000 }, { 0xffff, 0xffff, 0xffff, 0xffff }},
{ "gray", { 0x7dee, 0x8000, 0x8000 }, { 0xffff, 0x8080, 0x8080, 0x8080 }},
{ "black", { 0x1000, 0x8000, 0x8000 }, { 0xffff, 0x0000, 0x0000, 0x0000 }},
{ "red", { 0x4988, 0x60b9, 0xf000 }, { 0xffff, 0xffff, 0x0000, 0x0000 }},
{ "green", { 0xa47b, 0x2f47, 0x1902 }, { 0xffff, 0x0000, 0xffff, 0x0000 }},
{ "blue", { 0x1cfd, 0xf000, 0x76fe }, { 0xffff, 0x0000, 0x0000, 0xffff }},
}
},
};
/*
* vkms_format_test_yuv_u8_to_argb_u16 - Testing the conversion between YUV
* vkms_format_test_yuv_u16_to_argb_u16 - Testing the conversion between YUV
* colors to ARGB colors in VKMS
*
* This test will use the functions get_conversion_matrix_to_argb_u16 and
* argb_u16_from_yuv888 to convert YUV colors (stored in
* yuv_u8_to_argb_u16_cases) into ARGB colors.
* argb_u16_from_yuv161616 to convert YUV colors (stored in
* yuv_u16_to_argb_u16_cases) into ARGB colors.
*
* The conversion between YUV and RGB is not totally reversible, so there may be
* some difference between the expected value and the result.
* In addition, there may be some rounding error as the input color is 8 bits
* and output color is 16 bits.
*/
static void vkms_format_test_yuv_u8_to_argb_u16(struct kunit *test)
static void vkms_format_test_yuv_u16_to_argb_u16(struct kunit *test)
{
const struct yuv_u8_to_argb_u16_case *param = test->param_value;
const struct yuv_u16_to_argb_u16_case *param = test->param_value;
struct pixel_argb_u16 argb;
for (size_t i = 0; i < param->n_colors; i++) {
@@ -236,7 +234,8 @@ static void vkms_format_test_yuv_u8_to_argb_u16(struct kunit *test)
get_conversion_matrix_to_argb_u16
(DRM_FORMAT_NV12, param->encoding, param->range, &matrix);
argb = argb_u16_from_yuv888(color->yuv.y, color->yuv.u, color->yuv.v, &matrix);
argb = argb_u16_from_yuv161616(&matrix, color->yuv.y, color->yuv.u,
color->yuv.v);
KUNIT_EXPECT_LE_MSG(test, abs_diff(argb.a, color->argb.a), 0x1ff,
"On the A channel of the color %s expected 0x%04x, got 0x%04x",
@@ -253,19 +252,19 @@ static void vkms_format_test_yuv_u8_to_argb_u16(struct kunit *test)
}
}
static void vkms_format_test_yuv_u8_to_argb_u16_case_desc(struct yuv_u8_to_argb_u16_case *t,
char *desc)
static void vkms_format_test_yuv_u16_to_argb_u16_case_desc(struct yuv_u16_to_argb_u16_case *t,
char *desc)
{
snprintf(desc, KUNIT_PARAM_DESC_SIZE, "%s - %s",
drm_get_color_encoding_name(t->encoding), drm_get_color_range_name(t->range));
}
KUNIT_ARRAY_PARAM(yuv_u8_to_argb_u16, yuv_u8_to_argb_u16_cases,
vkms_format_test_yuv_u8_to_argb_u16_case_desc
KUNIT_ARRAY_PARAM(yuv_u16_to_argb_u16, yuv_u16_to_argb_u16_cases,
vkms_format_test_yuv_u16_to_argb_u16_case_desc
);
static struct kunit_case vkms_format_test_cases[] = {
KUNIT_CASE_PARAM(vkms_format_test_yuv_u8_to_argb_u16, yuv_u8_to_argb_u16_gen_params),
KUNIT_CASE_PARAM(vkms_format_test_yuv_u16_to_argb_u16, yuv_u16_to_argb_u16_gen_params),
{}
};

View File

@@ -259,16 +259,27 @@ static struct pixel_argb_u16 argb_u16_from_grayu16(u16 gray)
return argb_u16_from_u16161616(0xFFFF, gray, gray, gray);
}
VISIBLE_IF_KUNIT struct pixel_argb_u16 argb_u16_from_yuv888(u8 y, u8 channel_1, u8 channel_2,
const struct conversion_matrix *matrix)
static struct pixel_argb_u16 argb_u16_from_BGR565(const __le16 *pixel)
{
struct pixel_argb_u16 out_pixel;
out_pixel = argb_u16_from_RGB565(pixel);
swap(out_pixel.r, out_pixel.b);
return out_pixel;
}
VISIBLE_IF_KUNIT
struct pixel_argb_u16 argb_u16_from_yuv161616(const struct conversion_matrix *matrix,
u16 y, u16 channel_1, u16 channel_2)
{
u16 r, g, b;
s64 fp_y, fp_channel_1, fp_channel_2;
s64 fp_r, fp_g, fp_b;
fp_y = drm_int2fixp(((int)y - matrix->y_offset) * 257);
fp_channel_1 = drm_int2fixp(((int)channel_1 - 128) * 257);
fp_channel_2 = drm_int2fixp(((int)channel_2 - 128) * 257);
fp_y = drm_int2fixp((int)y - matrix->y_offset * 257);
fp_channel_1 = drm_int2fixp((int)channel_1 - 128 * 257);
fp_channel_2 = drm_int2fixp((int)channel_2 - 128 * 257);
fp_r = drm_fixp_mul(matrix->matrix[0][0], fp_y) +
drm_fixp_mul(matrix->matrix[0][1], fp_channel_1) +
@@ -290,7 +301,65 @@ VISIBLE_IF_KUNIT struct pixel_argb_u16 argb_u16_from_yuv888(u8 y, u8 channel_1,
return argb_u16_from_u16161616(0xffff, r, g, b);
}
EXPORT_SYMBOL_IF_KUNIT(argb_u16_from_yuv888);
EXPORT_SYMBOL_IF_KUNIT(argb_u16_from_yuv161616);
/**
* READ_LINE() - Generic generator for a read_line function which can be used for format with one
* plane and a block_h == block_w == 1.
*
* @function_name: Function name to generate
* @pixel_name: Temporary pixel name used in the @__VA_ARGS__ parameters
* @pixel_type: Used to specify the type you want to cast the pixel pointer
* @callback: Callback to call for each pixels. This fonction should take @__VA_ARGS__ as parameter
* and return a pixel_argb_u16
* __VA_ARGS__: Argument to pass inside the callback. You can use @pixel_name to access current
* pixel.
*/
#define READ_LINE(function_name, pixel_name, pixel_type, callback, ...) \
static void function_name(const struct vkms_plane_state *plane, int x_start, \
int y_start, enum pixel_read_direction direction, int count, \
struct pixel_argb_u16 out_pixel[]) \
{ \
struct pixel_argb_u16 *end = out_pixel + count; \
int step = get_block_step_bytes(plane->frame_info->fb, direction, 0); \
u8 *src_pixels; \
\
packed_pixels_addr_1x1(plane->frame_info, x_start, y_start, 0, &src_pixels); \
\
while (out_pixel < end) { \
pixel_type *(pixel_name) = (pixel_type *)src_pixels; \
*out_pixel = (callback)(__VA_ARGS__); \
out_pixel += 1; \
src_pixels += step; \
} \
}
/**
* READ_LINE_ARGB8888() - Generic generator for ARGB8888 formats.
* The pixel type used is u8, so pixel_name[0]..pixel_name[n] are the n components of the pixel.
*
* @function_name: Function name to generate
* @pixel_name: temporary pixel to use in @a, @r, @g and @b parameters
* @a: alpha value
* @r: red value
* @g: green value
* @b: blue value
*/
#define READ_LINE_ARGB8888(function_name, pixel_name, a, r, g, b) \
READ_LINE(function_name, pixel_name, u8, argb_u16_from_u8888, a, r, g, b)
/**
* READ_LINE_le16161616() - Generic generator for ARGB16161616 formats.
* The pixel type used is u16, so pixel_name[0]..pixel_name[n] are the n components of the pixel.
*
* @function_name: Function name to generate
* @pixel_name: temporary pixel to use in @a, @r, @g and @b parameters
* @a: alpha value
* @r: red value
* @g: green value
* @b: blue value
*/
#define READ_LINE_le16161616(function_name, pixel_name, a, r, g, b) \
READ_LINE(function_name, pixel_name, __le16, argb_u16_from_le16161616, a, r, g, b)
/*
* The following functions are read_line function for each pixel format supported by VKMS.
@@ -378,138 +447,27 @@ static void R4_read_line(const struct vkms_plane_state *plane, int x_start,
Rx_read_line(plane, x_start, y_start, direction, count, out_pixel);
}
static void R8_read_line(const struct vkms_plane_state *plane, int x_start,
int y_start, enum pixel_read_direction direction, int count,
struct pixel_argb_u16 out_pixel[])
{
struct pixel_argb_u16 *end = out_pixel + count;
u8 *src_pixels;
int step = get_block_step_bytes(plane->frame_info->fb, direction, 0);
packed_pixels_addr_1x1(plane->frame_info, x_start, y_start, 0, &src_pixels);
READ_LINE_ARGB8888(XRGB8888_read_line, px, 0xFF, px[2], px[1], px[0])
READ_LINE_ARGB8888(XBGR8888_read_line, px, 0xFF, px[0], px[1], px[2])
while (out_pixel < end) {
*out_pixel = argb_u16_from_gray8(*src_pixels);
src_pixels += step;
out_pixel += 1;
}
}
READ_LINE_ARGB8888(ARGB8888_read_line, px, px[3], px[2], px[1], px[0])
READ_LINE_ARGB8888(ABGR8888_read_line, px, px[3], px[0], px[1], px[2])
READ_LINE_ARGB8888(RGBA8888_read_line, px, px[0], px[3], px[2], px[1])
READ_LINE_ARGB8888(BGRA8888_read_line, px, px[0], px[1], px[2], px[3])
static void ARGB8888_read_line(const struct vkms_plane_state *plane, int x_start, int y_start,
enum pixel_read_direction direction, int count,
struct pixel_argb_u16 out_pixel[])
{
struct pixel_argb_u16 *end = out_pixel + count;
u8 *src_pixels;
READ_LINE_ARGB8888(RGB888_read_line, px, 0xFF, px[2], px[1], px[0])
READ_LINE_ARGB8888(BGR888_read_line, px, 0xFF, px[0], px[1], px[2])
packed_pixels_addr_1x1(plane->frame_info, x_start, y_start, 0, &src_pixels);
READ_LINE_le16161616(ARGB16161616_read_line, px, px[3], px[2], px[1], px[0])
READ_LINE_le16161616(ABGR16161616_read_line, px, px[3], px[0], px[1], px[2])
READ_LINE_le16161616(XRGB16161616_read_line, px, cpu_to_le16(0xFFFF), px[2], px[1], px[0])
READ_LINE_le16161616(XBGR16161616_read_line, px, cpu_to_le16(0xFFFF), px[0], px[1], px[2])
int step = get_block_step_bytes(plane->frame_info->fb, direction, 0);
READ_LINE(RGB565_read_line, px, __le16, argb_u16_from_RGB565, px)
READ_LINE(BGR565_read_line, px, __le16, argb_u16_from_BGR565, px)
while (out_pixel < end) {
u8 *px = (u8 *)src_pixels;
*out_pixel = argb_u16_from_u8888(px[3], px[2], px[1], px[0]);
out_pixel += 1;
src_pixels += step;
}
}
static void XRGB8888_read_line(const struct vkms_plane_state *plane, int x_start, int y_start,
enum pixel_read_direction direction, int count,
struct pixel_argb_u16 out_pixel[])
{
struct pixel_argb_u16 *end = out_pixel + count;
u8 *src_pixels;
packed_pixels_addr_1x1(plane->frame_info, x_start, y_start, 0, &src_pixels);
int step = get_block_step_bytes(plane->frame_info->fb, direction, 0);
while (out_pixel < end) {
u8 *px = (u8 *)src_pixels;
*out_pixel = argb_u16_from_u8888(255, px[2], px[1], px[0]);
out_pixel += 1;
src_pixels += step;
}
}
static void ABGR8888_read_line(const struct vkms_plane_state *plane, int x_start, int y_start,
enum pixel_read_direction direction, int count,
struct pixel_argb_u16 out_pixel[])
{
struct pixel_argb_u16 *end = out_pixel + count;
u8 *src_pixels;
packed_pixels_addr_1x1(plane->frame_info, x_start, y_start, 0, &src_pixels);
int step = get_block_step_bytes(plane->frame_info->fb, direction, 0);
while (out_pixel < end) {
u8 *px = (u8 *)src_pixels;
/* Switch blue and red pixels. */
*out_pixel = argb_u16_from_u8888(px[3], px[0], px[1], px[2]);
out_pixel += 1;
src_pixels += step;
}
}
static void ARGB16161616_read_line(const struct vkms_plane_state *plane, int x_start,
int y_start, enum pixel_read_direction direction, int count,
struct pixel_argb_u16 out_pixel[])
{
struct pixel_argb_u16 *end = out_pixel + count;
u8 *src_pixels;
packed_pixels_addr_1x1(plane->frame_info, x_start, y_start, 0, &src_pixels);
int step = get_block_step_bytes(plane->frame_info->fb, direction, 0);
while (out_pixel < end) {
u16 *px = (u16 *)src_pixels;
*out_pixel = argb_u16_from_u16161616(px[3], px[2], px[1], px[0]);
out_pixel += 1;
src_pixels += step;
}
}
static void XRGB16161616_read_line(const struct vkms_plane_state *plane, int x_start,
int y_start, enum pixel_read_direction direction, int count,
struct pixel_argb_u16 out_pixel[])
{
struct pixel_argb_u16 *end = out_pixel + count;
u8 *src_pixels;
packed_pixels_addr_1x1(plane->frame_info, x_start, y_start, 0, &src_pixels);
int step = get_block_step_bytes(plane->frame_info->fb, direction, 0);
while (out_pixel < end) {
__le16 *px = (__le16 *)src_pixels;
*out_pixel = argb_u16_from_le16161616(cpu_to_le16(0xFFFF), px[2], px[1], px[0]);
out_pixel += 1;
src_pixels += step;
}
}
static void RGB565_read_line(const struct vkms_plane_state *plane, int x_start,
int y_start, enum pixel_read_direction direction, int count,
struct pixel_argb_u16 out_pixel[])
{
struct pixel_argb_u16 *end = out_pixel + count;
u8 *src_pixels;
packed_pixels_addr_1x1(plane->frame_info, x_start, y_start, 0, &src_pixels);
int step = get_block_step_bytes(plane->frame_info->fb, direction, 0);
while (out_pixel < end) {
__le16 *px = (__le16 *)src_pixels;
*out_pixel = argb_u16_from_RGB565(px);
out_pixel += 1;
src_pixels += step;
}
}
READ_LINE(R8_read_line, px, u8, argb_u16_from_gray8, *px)
/*
* This callback can be used for YUV formats where U and V values are
@@ -521,35 +479,57 @@ static void RGB565_read_line(const struct vkms_plane_state *plane, int x_start,
* - Convert YUV and YVU with the same function (a column swap is needed when setting up
* plane->conversion_matrix)
*/
static void semi_planar_yuv_read_line(const struct vkms_plane_state *plane, int x_start,
int y_start, enum pixel_read_direction direction, int count,
struct pixel_argb_u16 out_pixel[])
{
u8 *y_plane;
u8 *uv_plane;
packed_pixels_addr_1x1(plane->frame_info, x_start, y_start, 0,
&y_plane);
packed_pixels_addr_1x1(plane->frame_info,
x_start / plane->frame_info->fb->format->hsub,
y_start / plane->frame_info->fb->format->vsub, 1,
&uv_plane);
int step_y = get_block_step_bytes(plane->frame_info->fb, direction, 0);
int step_uv = get_block_step_bytes(plane->frame_info->fb, direction, 1);
int subsampling = get_subsampling(plane->frame_info->fb->format, direction);
int subsampling_offset = get_subsampling_offset(direction, x_start, y_start);
const struct conversion_matrix *conversion_matrix = &plane->conversion_matrix;
for (int i = 0; i < count; i++) {
*out_pixel = argb_u16_from_yuv888(y_plane[0], uv_plane[0], uv_plane[1],
conversion_matrix);
out_pixel += 1;
y_plane += step_y;
if ((i + subsampling_offset + 1) % subsampling == 0)
uv_plane += step_uv;
}
/**
* READ_LINE_YUV_SEMIPLANAR() - Generic generator for a read_line function which can be used for yuv
* formats with two planes and block_w == block_h == 1.
*
* @function_name: Function name to generate
* @pixel_1_name: temporary pixel name for the first plane used in the @__VA_ARGS__ parameters
* @pixel_2_name: temporary pixel name for the second plane used in the @__VA_ARGS__ parameters
* @pixel_1_type: Used to specify the type you want to cast the pixel pointer on the plane 1
* @pixel_2_type: Used to specify the type you want to cast the pixel pointer on the plane 2
* @callback: Callback to call for each pixels. This function should take
* (struct conversion_matrix*, @__VA_ARGS__) as parameter and return a pixel_argb_u16
* __VA_ARGS__: Argument to pass inside the callback. You can use @pixel_1_name and @pixel_2_name
* to access current pixel values
*/
#define READ_LINE_YUV_SEMIPLANAR(function_name, pixel_1_name, pixel_2_name, pixel_1_type, \
pixel_2_type, callback, ...) \
static void function_name(const struct vkms_plane_state *plane, int x_start, \
int y_start, enum pixel_read_direction direction, int count, \
struct pixel_argb_u16 out_pixel[]) \
{ \
u8 *plane_1; \
u8 *plane_2; \
\
packed_pixels_addr_1x1(plane->frame_info, x_start, y_start, 0, \
&plane_1); \
packed_pixels_addr_1x1(plane->frame_info, \
x_start / plane->frame_info->fb->format->hsub, \
y_start / plane->frame_info->fb->format->vsub, 1, \
&plane_2); \
int step_1 = get_block_step_bytes(plane->frame_info->fb, direction, 0); \
int step_2 = get_block_step_bytes(plane->frame_info->fb, direction, 1); \
int subsampling = get_subsampling(plane->frame_info->fb->format, direction); \
int subsampling_offset = get_subsampling_offset(direction, x_start, y_start); \
const struct conversion_matrix *conversion_matrix = &plane->conversion_matrix; \
\
for (int i = 0; i < count; i++) { \
pixel_1_type *(pixel_1_name) = (pixel_1_type *)plane_1; \
pixel_2_type *(pixel_2_name) = (pixel_2_type *)plane_2; \
*out_pixel = (callback)(conversion_matrix, __VA_ARGS__); \
out_pixel += 1; \
plane_1 += step_1; \
if ((i + subsampling_offset + 1) % subsampling == 0) \
plane_2 += step_2; \
} \
}
READ_LINE_YUV_SEMIPLANAR(YUV888_semiplanar_read_line, y, uv, u8, u8, argb_u16_from_yuv161616,
y[0] * 257, uv[0] * 257, uv[1] * 257)
READ_LINE_YUV_SEMIPLANAR(YUV161616_semiplanar_read_line, y, uv, u16, u16, argb_u16_from_yuv161616,
y[0], uv[0], uv[1])
/*
* This callback can be used for YUV format where each color component is
* stored in a different plane (often called planar formats). It will
@@ -586,8 +566,9 @@ static void planar_yuv_read_line(const struct vkms_plane_state *plane, int x_sta
const struct conversion_matrix *conversion_matrix = &plane->conversion_matrix;
for (int i = 0; i < count; i++) {
*out_pixel = argb_u16_from_yuv888(*y_plane, *channel_1_plane, *channel_2_plane,
conversion_matrix);
*out_pixel = argb_u16_from_yuv161616(conversion_matrix,
*y_plane * 257, *channel_1_plane * 257,
*channel_2_plane * 257);
out_pixel += 1;
y_plane += step_y;
if ((i + subsampling_offset + 1) % subsampling == 0) {
@@ -712,23 +693,43 @@ pixel_read_line_t get_pixel_read_line_function(u32 format)
switch (format) {
case DRM_FORMAT_ARGB8888:
return &ARGB8888_read_line;
case DRM_FORMAT_XRGB8888:
return &XRGB8888_read_line;
case DRM_FORMAT_ABGR8888:
return &ABGR8888_read_line;
case DRM_FORMAT_BGRA8888:
return &BGRA8888_read_line;
case DRM_FORMAT_RGBA8888:
return &RGBA8888_read_line;
case DRM_FORMAT_XRGB8888:
return &XRGB8888_read_line;
case DRM_FORMAT_XBGR8888:
return &XBGR8888_read_line;
case DRM_FORMAT_RGB888:
return &RGB888_read_line;
case DRM_FORMAT_BGR888:
return &BGR888_read_line;
case DRM_FORMAT_ARGB16161616:
return &ARGB16161616_read_line;
case DRM_FORMAT_ABGR16161616:
return &ABGR16161616_read_line;
case DRM_FORMAT_XRGB16161616:
return &XRGB16161616_read_line;
case DRM_FORMAT_XBGR16161616:
return &XBGR16161616_read_line;
case DRM_FORMAT_RGB565:
return &RGB565_read_line;
case DRM_FORMAT_BGR565:
return &BGR565_read_line;
case DRM_FORMAT_NV12:
case DRM_FORMAT_NV16:
case DRM_FORMAT_NV24:
case DRM_FORMAT_NV21:
case DRM_FORMAT_NV61:
case DRM_FORMAT_NV42:
return &semi_planar_yuv_read_line;
return &YUV888_semiplanar_read_line;
case DRM_FORMAT_P010:
case DRM_FORMAT_P012:
case DRM_FORMAT_P016:
return &YUV161616_semiplanar_read_line;
case DRM_FORMAT_YUV420:
case DRM_FORMAT_YUV422:
case DRM_FORMAT_YUV444:

View File

@@ -14,8 +14,8 @@ void get_conversion_matrix_to_argb_u16(u32 format, enum drm_color_encoding encod
struct conversion_matrix *matrix);
#if IS_ENABLED(CONFIG_KUNIT)
struct pixel_argb_u16 argb_u16_from_yuv888(u8 y, u8 channel_1, u8 channel_2,
const struct conversion_matrix *matrix);
struct pixel_argb_u16 argb_u16_from_yuv161616(const struct conversion_matrix *matrix,
u16 y, u16 channel_1, u16 channel_2);
#endif
#endif /* _VKMS_FORMATS_H_ */

View File

@@ -14,11 +14,19 @@
static const u32 vkms_formats[] = {
DRM_FORMAT_ARGB8888,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_ABGR8888,
DRM_FORMAT_BGRA8888,
DRM_FORMAT_RGBA8888,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_XBGR8888,
DRM_FORMAT_RGB888,
DRM_FORMAT_BGR888,
DRM_FORMAT_XRGB16161616,
DRM_FORMAT_XBGR16161616,
DRM_FORMAT_ARGB16161616,
DRM_FORMAT_ABGR16161616,
DRM_FORMAT_RGB565,
DRM_FORMAT_BGR565,
DRM_FORMAT_NV12,
DRM_FORMAT_NV16,
DRM_FORMAT_NV24,
@@ -31,6 +39,9 @@ static const u32 vkms_formats[] = {
DRM_FORMAT_YVU420,
DRM_FORMAT_YVU422,
DRM_FORMAT_YVU444,
DRM_FORMAT_P010,
DRM_FORMAT_P012,
DRM_FORMAT_P016,
DRM_FORMAT_R1,
DRM_FORMAT_R2,
DRM_FORMAT_R4,

View File

@@ -191,10 +191,22 @@ struct dma_buf *xe_gem_prime_export(struct drm_gem_object *obj, int flags)
{
struct xe_bo *bo = gem_to_xe_bo(obj);
struct dma_buf *buf;
struct ttm_operation_ctx ctx = {
.interruptible = true,
.no_wait_gpu = true,
/* We opt to avoid OOM on system pages allocations */
.gfp_retry_mayfail = true,
.allow_res_evict = false,
};
int ret;
if (bo->vm)
return ERR_PTR(-EPERM);
ret = ttm_bo_setup_export(&bo->ttm, &ctx);
if (ret)
return ERR_PTR(ret);
buf = drm_gem_prime_export(obj, flags);
if (!IS_ERR(buf))
buf->ops = &xe_dmabuf_ops;

View File

@@ -556,34 +556,13 @@ EXPORT_SYMBOL(vga_put);
static bool vga_is_firmware_default(struct pci_dev *pdev)
{
#if defined(CONFIG_X86)
u64 base = screen_info.lfb_base;
u64 size = screen_info.lfb_size;
struct resource *r;
u64 limit;
#ifdef CONFIG_SCREEN_INFO
struct screen_info *si = &screen_info;
/* Select the device owning the boot framebuffer if there is one */
if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)
base |= (u64)screen_info.ext_lfb_base << 32;
limit = base + size;
/* Does firmware framebuffer belong to us? */
pci_dev_for_each_resource(pdev, r) {
if (resource_type(r) != IORESOURCE_MEM)
continue;
if (!r->start || !r->end)
continue;
if (base < r->start || limit >= r->end)
continue;
return true;
}
#endif
return pdev == screen_info_pci_dev(si);
#else
return false;
#endif
}
static bool vga_arb_integrated_gpu(struct device *dev)

View File

@@ -466,6 +466,8 @@ pgprot_t ttm_io_prot(struct ttm_buffer_object *bo, struct ttm_resource *res,
void ttm_bo_tt_destroy(struct ttm_buffer_object *bo);
int ttm_bo_populate(struct ttm_buffer_object *bo,
struct ttm_operation_ctx *ctx);
int ttm_bo_setup_export(struct ttm_buffer_object *bo,
struct ttm_operation_ctx *ctx);
/* Driver LRU walk helpers initially targeted for shrinking. */

View File

@@ -34,6 +34,7 @@ enum amdxdna_drm_ioctl_id {
DRM_AMDXDNA_EXEC_CMD,
DRM_AMDXDNA_GET_INFO,
DRM_AMDXDNA_SET_STATE,
DRM_AMDXDNA_GET_ARRAY = 10,
};
/**
@@ -455,6 +456,112 @@ struct amdxdna_drm_get_info {
__u64 buffer; /* in/out */
};
#define AMDXDNA_HWCTX_STATE_IDLE 0
#define AMDXDNA_HWCTX_STATE_ACTIVE 1
/**
* struct amdxdna_drm_hwctx_entry - The hardware context array entry
*/
struct amdxdna_drm_hwctx_entry {
/** @context_id: Context ID. */
__u32 context_id;
/** @start_col: Start AIE array column assigned to context. */
__u32 start_col;
/** @num_col: Number of AIE array columns assigned to context. */
__u32 num_col;
/** @hwctx_id: The real hardware context id. */
__u32 hwctx_id;
/** @pid: ID of process which created this context. */
__s64 pid;
/** @command_submissions: Number of commands submitted. */
__u64 command_submissions;
/** @command_completions: Number of commands completed. */
__u64 command_completions;
/** @migrations: Number of times been migrated. */
__u64 migrations;
/** @preemptions: Number of times been preempted. */
__u64 preemptions;
/** @errors: Number of errors happened. */
__u64 errors;
/** @priority: Context priority. */
__u64 priority;
/** @heap_usage: Usage of device heap buffer. */
__u64 heap_usage;
/** @suspensions: Number of times been suspended. */
__u64 suspensions;
/**
* @state: Context state.
* %AMDXDNA_HWCTX_STATE_IDLE
* %AMDXDNA_HWCTX_STATE_ACTIVE
*/
__u32 state;
/** @pasid: PASID been bound. */
__u32 pasid;
/** @gops: Giga operations per second. */
__u32 gops;
/** @fps: Frames per second. */
__u32 fps;
/** @dma_bandwidth: DMA bandwidth. */
__u32 dma_bandwidth;
/** @latency: Frame response latency. */
__u32 latency;
/** @frame_exec_time: Frame execution time. */
__u32 frame_exec_time;
/** @txn_op_idx: Index of last control code executed. */
__u32 txn_op_idx;
/** @ctx_pc: Program counter. */
__u32 ctx_pc;
/** @fatal_error_type: Fatal error type if context crashes. */
__u32 fatal_error_type;
/** @fatal_error_exception_type: Firmware exception type. */
__u32 fatal_error_exception_type;
/** @fatal_error_exception_pc: Firmware exception program counter. */
__u32 fatal_error_exception_pc;
/** @fatal_error_app_module: Exception module name. */
__u32 fatal_error_app_module;
/** @pad: Structure pad. */
__u32 pad;
};
#define DRM_AMDXDNA_HW_CONTEXT_ALL 0
/**
* struct amdxdna_drm_get_array - Get information array.
*/
struct amdxdna_drm_get_array {
/**
* @param:
*
* Supported params:
*
* %DRM_AMDXDNA_HW_CONTEXT_ALL:
* Returns all created hardware contexts.
*/
__u32 param;
/**
* @element_size:
*
* Specifies maximum element size and returns the actual element size.
*/
__u32 element_size;
/**
* @num_element:
*
* Specifies maximum number of elements and returns the actual number
* of elements.
*/
__u32 num_element; /* in/out */
/** @pad: MBZ */
__u32 pad;
/**
* @buffer:
*
* Specifies the match conditions and returns the matched information
* array.
*/
__u64 buffer;
};
enum amdxdna_drm_set_param {
DRM_AMDXDNA_SET_POWER_MODE,
DRM_AMDXDNA_WRITE_AIE_MEM,
@@ -519,6 +626,10 @@ struct amdxdna_drm_set_power_mode {
DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDXDNA_SET_STATE, \
struct amdxdna_drm_set_state)
#define DRM_IOCTL_AMDXDNA_GET_ARRAY \
DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDXDNA_GET_ARRAY, \
struct amdxdna_drm_get_array)
#if defined(__cplusplus)
} /* extern c end */
#endif