1
0

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

drm-misc-next for v6.19:

UAPI Changes:

amdxdna:
- Support reading last hardware error

Cross-subsystem Changes:

dma-buf:
- heaps: Create heap per CMA reserved location; Improve user-space documentation

Core Changes:

atomic:
- Clean up and improve state-handling interfaces, update drivers

bridge:
- Improve ref counting

buddy:
- Optimize block management

Driver Changes:

amdxdna:
- Fix runtime power management
- Support firmware debug output

ast:
- Set quirks for each chip model

atmel-hlcdc:
- Set LCDC_ATTRE register in plane disable
- Set correct values for plane scaler

bochs:
- Use vblank timer

bridge:
- synopsis: Support CEC; Init timer with correct frequency

cirrus-qemu:
- Use vblank timer

imx:
- Clean up

ivu:
- Update JSM API to 3.33.0
- Reset engine on more job errors
- Return correct error codes for jobs

komeda:
- Use drm_ logging functions

panel:
- edp: Support AUO B116XAN02.0

panfrost:
- Embed struct drm_driver in Panfrost device
- Improve error handling
- Clean up job handling

panthor:
- Support custom ASN_HASH for mt8196

renesas:
- rz-du: Fix dependencies

rockchip:
- dsi: Add support for RK3368
- Fix LUT size for RK3386

sitronix:
- Fix output position when clearing screens

qaic:
- Support dma-buf exports
- Support new firmware's READ_DATA implementation
- Replace kcalloc with memdup
- Replace snprintf() with sysfs_emit()
- Avoid overflows in arithmetics
- Clean up
- Fixes

qxl:
- Use vblank timer

rockchip:
- Clean up mode-setting code

vgem:
- Fix fence timer deadlock

virtgpu:
- Use vblank timer

Signed-off-by: Simona Vetter <simona.vetter@ffwll.ch>

From: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://lore.kernel.org/r/20251021111837.GA40643@linux.fritz.box
This commit is contained in:
Simona Vetter
2025-10-24 13:25:19 +02:00
138 changed files with 2496 additions and 1116 deletions

View File

@@ -17,6 +17,7 @@ properties:
- rockchip,px30-mipi-dsi
- rockchip,rk3128-mipi-dsi
- rockchip,rk3288-mipi-dsi
- rockchip,rk3368-mipi-dsi
- rockchip,rk3399-mipi-dsi
- rockchip,rk3568-mipi-dsi
- rockchip,rv1126-mipi-dsi
@@ -73,6 +74,7 @@ allOf:
enum:
- rockchip,px30-mipi-dsi
- rockchip,rk3128-mipi-dsi
- rockchip,rk3368-mipi-dsi
- rockchip,rk3568-mipi-dsi
- rockchip,rv1126-mipi-dsi

View File

@@ -18,6 +18,7 @@ properties:
oneOf:
- items:
- enum:
- mediatek,mt8196-mali
- rockchip,rk3588-mali
- const: arm,mali-valhall-csf # Mali Valhall GPU model/revision is fully discoverable
@@ -91,7 +92,6 @@ required:
- interrupts
- interrupt-names
- clocks
- mali-supply
additionalProperties: false
@@ -108,6 +108,8 @@ allOf:
power-domains:
maxItems: 1
power-domain-names: false
required:
- mali-supply
examples:
- |

View File

@@ -16,13 +16,52 @@ following heaps:
- The ``system`` heap allocates virtually contiguous, cacheable, buffers.
- The ``cma`` heap allocates physically contiguous, cacheable,
buffers. Only present if a CMA region is present. Such a region is
usually created either through the kernel commandline through the
``cma`` parameter, a memory region Device-Tree node with the
``linux,cma-default`` property set, or through the ``CMA_SIZE_MBYTES`` or
``CMA_SIZE_PERCENTAGE`` Kconfig options. The heap's name in devtmpfs is
``default_cma_region``. For backwards compatibility, when the
``DMABUF_HEAPS_CMA_LEGACY`` Kconfig option is set, a duplicate node is
created following legacy naming conventions; the legacy name might be
``reserved``, ``linux,cma``, or ``default-pool``.
- The ``default_cma_region`` heap allocates physically contiguous,
cacheable, buffers. Only present if a CMA region is present. Such a
region is usually created either through the kernel commandline
through the ``cma`` parameter, a memory region Device-Tree node with
the ``linux,cma-default`` property set, or through the
``CMA_SIZE_MBYTES`` or ``CMA_SIZE_PERCENTAGE`` Kconfig options. Prior
to Linux 6.17, its name wasn't stable and could be called
``reserved``, ``linux,cma``, or ``default-pool``, depending on the
platform.
- A heap will be created for each reusable region in the device tree
with the ``shared-dma-pool`` compatible, using the full device tree
node name as its name. The buffer semantics are identical to
``default-cma-region``.
Naming Convention
=================
``dma-buf`` heaps name should meet a number of constraints:
- The name must be stable, and must not change from one version to the other.
Userspace identifies heaps by their name, so if the names ever change, we
would be likely to introduce regressions.
- The name must describe the memory region the heap will allocate from, and
must uniquely identify it in a given platform. Since userspace applications
use the heap name as the discriminant, it must be able to tell which heap it
wants to use reliably if there's multiple heaps.
- The name must not mention implementation details, such as the allocator. The
heap driver will change over time, and implementation details when it was
introduced might not be relevant in the future.
- The name should describe properties of the buffers that would be allocated.
Doing so will make heap identification easier for userspace. Such properties
are:
- ``contiguous`` for physically contiguous buffers;
- ``protected`` for encrypted buffers not accessible the OS;
- The name may describe intended usage. Doing so will make heap identification
easier for userspace applications and users.
For example, assuming a platform with a reserved memory region located
at the RAM address 0x42000000, intended to allocate video framebuffers,
physically contiguous, and backed by the CMA kernel allocator, good
names would be ``memory@42000000-contiguous`` or ``video@42000000``, but
``cma-video`` wouldn't.

View File

@@ -2092,7 +2092,8 @@ F: drivers/gpu/drm/arm/display/komeda/
ARM MALI PANFROST DRM DRIVER
M: Boris Brezillon <boris.brezillon@collabora.com>
M: Rob Herring <robh@kernel.org>
R: Steven Price <steven.price@arm.com>
M: Steven Price <steven.price@arm.com>
M: Adrián Larumbe <adrian.larumbe@collabora.com>
L: dri-devel@lists.freedesktop.org
S: Supported
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
@@ -7309,6 +7310,7 @@ F: Documentation/userspace-api/dma-buf-alloc-exchange.rst
F: drivers/dma-buf/
F: include/linux/*fence.h
F: include/linux/dma-buf.h
F: include/linux/dma-buf/
F: include/linux/dma-resv.h
K: \bdma_(?:buf|fence|resv)\b
@@ -7637,7 +7639,6 @@ F: drivers/accel/
F: include/drm/drm_accel.h
DRM DRIVER FOR ALLWINNER DE2 AND DE3 ENGINE
M: Maxime Ripard <mripard@kernel.org>
M: Chen-Yu Tsai <wens@csie.org>
R: Jernej Skrabec <jernej.skrabec@gmail.com>
L: dri-devel@lists.freedesktop.org
@@ -7747,7 +7748,8 @@ F: Documentation/devicetree/bindings/display/panel/panel-edp.yaml
F: drivers/gpu/drm/panel/panel-edp.c
DRM DRIVER FOR GENERIC USB DISPLAY
S: Orphan
M: Ruben Wauters <rubenru09@aol.com>
S: Maintained
W: https://github.com/notro/gud/wiki
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
F: drivers/gpu/drm/gud/
@@ -7888,7 +7890,7 @@ DRM DRIVER for Qualcomm display hardware
M: Rob Clark <robin.clark@oss.qualcomm.com>
M: Dmitry Baryshkov <lumag@kernel.org>
R: Abhinav Kumar <abhinav.kumar@linux.dev>
R: Jessica Zhang <jessica.zhang@oss.qualcomm.com>
R: Jessica Zhang <jesszhan0024@gmail.com>
R: Sean Paul <sean@poorly.run>
R: Marijn Suijten <marijn.suijten@somainline.org>
L: linux-arm-msm@vger.kernel.org
@@ -8251,7 +8253,6 @@ F: drivers/gpu/nova-core/
F: rust/kernel/drm/
DRM DRIVERS FOR ALLWINNER A10
M: Maxime Ripard <mripard@kernel.org>
M: Chen-Yu Tsai <wens@csie.org>
L: dri-devel@lists.freedesktop.org
S: Supported
@@ -8601,7 +8602,7 @@ F: drivers/gpu/drm/clients/drm_log.c
DRM PANEL DRIVERS
M: Neil Armstrong <neil.armstrong@linaro.org>
R: Jessica Zhang <jessica.zhang@oss.qualcomm.com>
R: Jessica Zhang <jesszhan0024@gmail.com>
L: dri-devel@lists.freedesktop.org
S: Maintained
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git

View File

@@ -1,2 +1 @@
- Add debugfs support
- Add debug BO support

View File

@@ -226,11 +226,10 @@ out:
}
static int
aie2_sched_nocmd_resp_handler(void *handle, void __iomem *data, size_t size)
aie2_sched_drvcmd_resp_handler(void *handle, void __iomem *data, size_t size)
{
struct amdxdna_sched_job *job = handle;
int ret = 0;
u32 status;
if (unlikely(!data))
goto out;
@@ -240,8 +239,7 @@ aie2_sched_nocmd_resp_handler(void *handle, void __iomem *data, size_t size)
goto out;
}
status = readl(data);
XDNA_DBG(job->hwctx->client->xdna, "Resp status 0x%x", status);
job->drv_cmd->result = readl(data);
out:
aie2_sched_notify(job);
@@ -314,8 +312,18 @@ aie2_sched_job_run(struct drm_sched_job *sched_job)
kref_get(&job->refcnt);
fence = dma_fence_get(job->fence);
if (unlikely(!cmd_abo)) {
ret = aie2_sync_bo(hwctx, job, aie2_sched_nocmd_resp_handler);
if (job->drv_cmd) {
switch (job->drv_cmd->opcode) {
case SYNC_DEBUG_BO:
ret = aie2_sync_bo(hwctx, job, aie2_sched_drvcmd_resp_handler);
break;
case ATTACH_DEBUG_BO:
ret = aie2_config_debug_bo(hwctx, job, aie2_sched_drvcmd_resp_handler);
break;
default:
ret = -EINVAL;
break;
}
goto out;
}
@@ -610,10 +618,14 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
goto free_entity;
}
ret = amdxdna_pm_resume_get(xdna);
if (ret)
goto free_col_list;
ret = aie2_alloc_resource(hwctx);
if (ret) {
XDNA_ERR(xdna, "Alloc hw resource failed, ret %d", ret);
goto free_col_list;
goto suspend_put;
}
ret = aie2_map_host_buf(xdna->dev_handle, hwctx->fw_ctx_id,
@@ -628,6 +640,7 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
XDNA_ERR(xdna, "Create syncobj failed, ret %d", ret);
goto release_resource;
}
amdxdna_pm_suspend_put(xdna);
hwctx->status = HWCTX_STAT_INIT;
ndev = xdna->dev_handle;
@@ -640,6 +653,8 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
release_resource:
aie2_release_resource(hwctx);
suspend_put:
amdxdna_pm_suspend_put(xdna);
free_col_list:
kfree(hwctx->col_list);
free_entity:
@@ -759,6 +774,74 @@ free_cus:
return ret;
}
static void aie2_cmd_wait(struct amdxdna_hwctx *hwctx, u64 seq)
{
struct dma_fence *out_fence = aie2_cmd_get_out_fence(hwctx, seq);
if (!out_fence) {
XDNA_ERR(hwctx->client->xdna, "Failed to get fence");
return;
}
dma_fence_wait_timeout(out_fence, false, MAX_SCHEDULE_TIMEOUT);
dma_fence_put(out_fence);
}
static int aie2_hwctx_cfg_debug_bo(struct amdxdna_hwctx *hwctx, u32 bo_hdl,
bool attach)
{
struct amdxdna_client *client = hwctx->client;
struct amdxdna_dev *xdna = client->xdna;
struct amdxdna_drv_cmd cmd = { 0 };
struct amdxdna_gem_obj *abo;
u64 seq;
int ret;
abo = amdxdna_gem_get_obj(client, bo_hdl, AMDXDNA_BO_DEV);
if (!abo) {
XDNA_ERR(xdna, "Get bo %d failed", bo_hdl);
return -EINVAL;
}
if (attach) {
if (abo->assigned_hwctx != AMDXDNA_INVALID_CTX_HANDLE) {
ret = -EBUSY;
goto put_obj;
}
cmd.opcode = ATTACH_DEBUG_BO;
} else {
if (abo->assigned_hwctx != hwctx->id) {
ret = -EINVAL;
goto put_obj;
}
cmd.opcode = DETACH_DEBUG_BO;
}
ret = amdxdna_cmd_submit(client, &cmd, AMDXDNA_INVALID_BO_HANDLE,
&bo_hdl, 1, hwctx->id, &seq);
if (ret) {
XDNA_ERR(xdna, "Submit command failed");
goto put_obj;
}
aie2_cmd_wait(hwctx, seq);
if (cmd.result) {
XDNA_ERR(xdna, "Response failure 0x%x", cmd.result);
goto put_obj;
}
if (attach)
abo->assigned_hwctx = hwctx->id;
else
abo->assigned_hwctx = AMDXDNA_INVALID_CTX_HANDLE;
XDNA_DBG(xdna, "Config debug BO %d to %s", bo_hdl, hwctx->name);
put_obj:
amdxdna_gem_put_obj(abo);
return ret;
}
int aie2_hwctx_config(struct amdxdna_hwctx *hwctx, u32 type, u64 value, void *buf, u32 size)
{
struct amdxdna_dev *xdna = hwctx->client->xdna;
@@ -768,14 +851,40 @@ int aie2_hwctx_config(struct amdxdna_hwctx *hwctx, u32 type, u64 value, void *bu
case DRM_AMDXDNA_HWCTX_CONFIG_CU:
return aie2_hwctx_cu_config(hwctx, buf, size);
case DRM_AMDXDNA_HWCTX_ASSIGN_DBG_BUF:
return aie2_hwctx_cfg_debug_bo(hwctx, (u32)value, true);
case DRM_AMDXDNA_HWCTX_REMOVE_DBG_BUF:
return -EOPNOTSUPP;
return aie2_hwctx_cfg_debug_bo(hwctx, (u32)value, false);
default:
XDNA_DBG(xdna, "Not supported type %d", type);
return -EOPNOTSUPP;
}
}
int aie2_hwctx_sync_debug_bo(struct amdxdna_hwctx *hwctx, u32 debug_bo_hdl)
{
struct amdxdna_client *client = hwctx->client;
struct amdxdna_dev *xdna = client->xdna;
struct amdxdna_drv_cmd cmd = { 0 };
u64 seq;
int ret;
cmd.opcode = SYNC_DEBUG_BO;
ret = amdxdna_cmd_submit(client, &cmd, AMDXDNA_INVALID_BO_HANDLE,
&debug_bo_hdl, 1, hwctx->id, &seq);
if (ret) {
XDNA_ERR(xdna, "Submit command failed");
return ret;
}
aie2_cmd_wait(hwctx, seq);
if (cmd.result) {
XDNA_ERR(xdna, "Response failure 0x%x", cmd.result);
return ret;
}
return 0;
}
static int aie2_populate_range(struct amdxdna_gem_obj *abo)
{
struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(abo)->dev);

View File

@@ -13,6 +13,7 @@
#include "aie2_msg_priv.h"
#include "aie2_pci.h"
#include "amdxdna_error.h"
#include "amdxdna_mailbox.h"
#include "amdxdna_pci_drv.h"
@@ -46,6 +47,7 @@ enum aie_module_type {
AIE_MEM_MOD = 0,
AIE_CORE_MOD,
AIE_PL_MOD,
AIE_UNKNOWN_MOD,
};
enum aie_error_category {
@@ -143,6 +145,31 @@ static const struct aie_event_category aie_ml_shim_tile_event_cat[] = {
EVENT_CATEGORY(74U, AIE_ERROR_LOCK),
};
static const enum amdxdna_error_num aie_cat_err_num_map[] = {
[AIE_ERROR_SATURATION] = AMDXDNA_ERROR_NUM_AIE_SATURATION,
[AIE_ERROR_FP] = AMDXDNA_ERROR_NUM_AIE_FP,
[AIE_ERROR_STREAM] = AMDXDNA_ERROR_NUM_AIE_STREAM,
[AIE_ERROR_ACCESS] = AMDXDNA_ERROR_NUM_AIE_ACCESS,
[AIE_ERROR_BUS] = AMDXDNA_ERROR_NUM_AIE_BUS,
[AIE_ERROR_INSTRUCTION] = AMDXDNA_ERROR_NUM_AIE_INSTRUCTION,
[AIE_ERROR_ECC] = AMDXDNA_ERROR_NUM_AIE_ECC,
[AIE_ERROR_LOCK] = AMDXDNA_ERROR_NUM_AIE_LOCK,
[AIE_ERROR_DMA] = AMDXDNA_ERROR_NUM_AIE_DMA,
[AIE_ERROR_MEM_PARITY] = AMDXDNA_ERROR_NUM_AIE_MEM_PARITY,
[AIE_ERROR_UNKNOWN] = AMDXDNA_ERROR_NUM_UNKNOWN,
};
static_assert(ARRAY_SIZE(aie_cat_err_num_map) == AIE_ERROR_UNKNOWN + 1);
static const enum amdxdna_error_module aie_err_mod_map[] = {
[AIE_MEM_MOD] = AMDXDNA_ERROR_MODULE_AIE_MEMORY,
[AIE_CORE_MOD] = AMDXDNA_ERROR_MODULE_AIE_CORE,
[AIE_PL_MOD] = AMDXDNA_ERROR_MODULE_AIE_PL,
[AIE_UNKNOWN_MOD] = AMDXDNA_ERROR_MODULE_UNKNOWN,
};
static_assert(ARRAY_SIZE(aie_err_mod_map) == AIE_UNKNOWN_MOD + 1);
static enum aie_error_category
aie_get_error_category(u8 row, u8 event_id, enum aie_module_type mod_type)
{
@@ -176,12 +203,40 @@ aie_get_error_category(u8 row, u8 event_id, enum aie_module_type mod_type)
if (event_id != lut[i].event_id)
continue;
if (lut[i].category > AIE_ERROR_UNKNOWN)
return AIE_ERROR_UNKNOWN;
return lut[i].category;
}
return AIE_ERROR_UNKNOWN;
}
static void aie2_update_last_async_error(struct amdxdna_dev_hdl *ndev, void *err_info, u32 num_err)
{
struct aie_error *errs = err_info;
enum amdxdna_error_module err_mod;
enum aie_error_category aie_err;
enum amdxdna_error_num err_num;
struct aie_error *last_err;
last_err = &errs[num_err - 1];
if (last_err->mod_type >= AIE_UNKNOWN_MOD) {
err_num = aie_cat_err_num_map[AIE_ERROR_UNKNOWN];
err_mod = aie_err_mod_map[AIE_UNKNOWN_MOD];
} else {
aie_err = aie_get_error_category(last_err->row,
last_err->event_id,
last_err->mod_type);
err_num = aie_cat_err_num_map[aie_err];
err_mod = aie_err_mod_map[last_err->mod_type];
}
ndev->last_async_err.err_code = AMDXDNA_ERROR_ENCODE(err_num, err_mod);
ndev->last_async_err.ts_us = ktime_to_us(ktime_get_real());
ndev->last_async_err.ex_err_code = AMDXDNA_EXTRA_ERR_ENCODE(last_err->row, last_err->col);
}
static u32 aie2_error_backtrack(struct amdxdna_dev_hdl *ndev, void *err_info, u32 num_err)
{
struct aie_error *errs = err_info;
@@ -264,29 +319,14 @@ static void aie2_error_worker(struct work_struct *err_work)
}
mutex_lock(&xdna->dev_lock);
aie2_update_last_async_error(e->ndev, info->payload, info->err_cnt);
/* Re-sent this event to firmware */
if (aie2_error_event_send(e))
XDNA_WARN(xdna, "Unable to register async event");
mutex_unlock(&xdna->dev_lock);
}
int aie2_error_async_events_send(struct amdxdna_dev_hdl *ndev)
{
struct amdxdna_dev *xdna = ndev->xdna;
struct async_event *e;
int i, ret;
drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock));
for (i = 0; i < ndev->async_events->event_cnt; i++) {
e = &ndev->async_events->event[i];
ret = aie2_error_event_send(e);
if (ret)
return ret;
}
return 0;
}
void aie2_error_async_events_free(struct amdxdna_dev_hdl *ndev)
{
struct amdxdna_dev *xdna = ndev->xdna;
@@ -341,6 +381,10 @@ int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev)
e->size = ASYNC_BUF_SIZE;
e->resp.status = MAX_AIE2_STATUS_CODE;
INIT_WORK(&e->work, aie2_error_worker);
ret = aie2_error_event_send(e);
if (ret)
goto free_wq;
}
ndev->async_events = events;
@@ -349,6 +393,8 @@ int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev)
events->event_cnt, events->size);
return 0;
free_wq:
destroy_workqueue(events->wq);
free_buf:
dma_free_noncoherent(xdna->ddev.dev, events->size, events->buf,
events->addr, DMA_FROM_DEVICE);
@@ -356,3 +402,18 @@ free_events:
kfree(events);
return ret;
}
int aie2_get_array_async_error(struct amdxdna_dev_hdl *ndev, struct amdxdna_drm_get_array *args)
{
struct amdxdna_dev *xdna = ndev->xdna;
drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock));
args->num_element = 1;
args->element_size = sizeof(ndev->last_async_err);
if (copy_to_user(u64_to_user_ptr(args->buffer),
&ndev->last_async_err, args->element_size))
return -EFAULT;
return 0;
}

View File

@@ -749,7 +749,7 @@ int aie2_sync_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job,
int ret = 0;
req.src_addr = 0;
req.dst_addr = abo->mem.dev_addr - hwctx->client->dev_heap->mem.dev_addr;
req.dst_addr = amdxdna_dev_bo_offset(abo);
req.size = abo->mem.size;
/* Device to Host */
@@ -773,3 +773,32 @@ int aie2_sync_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job,
return 0;
}
int aie2_config_debug_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job,
int (*notify_cb)(void *, void __iomem *, size_t))
{
struct mailbox_channel *chann = hwctx->priv->mbox_chann;
struct amdxdna_gem_obj *abo = to_xdna_obj(job->bos[0]);
struct amdxdna_dev *xdna = hwctx->client->xdna;
struct config_debug_bo_req req;
struct xdna_mailbox_msg msg;
if (job->drv_cmd->opcode == ATTACH_DEBUG_BO)
req.config = DEBUG_BO_REGISTER;
else
req.config = DEBUG_BO_UNREGISTER;
req.offset = amdxdna_dev_bo_offset(abo);
req.size = abo->mem.size;
XDNA_DBG(xdna, "offset 0x%llx size 0x%llx config %d",
req.offset, req.size, req.config);
msg.handle = job;
msg.notify_cb = notify_cb;
msg.send_data = (u8 *)&req;
msg.send_size = sizeof(req);
msg.opcode = MSG_OP_CONFIG_DEBUG_BO;
return xdna_mailbox_send_msg(chann, &msg, TX_TIMEOUT);
}

View File

@@ -18,6 +18,7 @@ enum aie2_msg_opcode {
MSG_OP_CONFIG_CU = 0x11,
MSG_OP_CHAIN_EXEC_BUFFER_CF = 0x12,
MSG_OP_CHAIN_EXEC_DPU = 0x13,
MSG_OP_CONFIG_DEBUG_BO = 0x14,
MSG_OP_MAX_XRT_OPCODE,
MSG_OP_SUSPEND = 0x101,
MSG_OP_RESUME = 0x102,
@@ -365,4 +366,21 @@ struct sync_bo_req {
struct sync_bo_resp {
enum aie2_msg_status status;
} __packed;
#define DEBUG_BO_UNREGISTER 0
#define DEBUG_BO_REGISTER 1
struct config_debug_bo_req {
__u64 offset;
__u64 size;
/*
* config operations.
* DEBUG_BO_REGISTER: Register debug buffer
* DEBUG_BO_UNREGISTER: Unregister debug buffer
*/
__u32 config;
} __packed;
struct config_debug_bo_resp {
enum aie2_msg_status status;
} __packed;
#endif /* _AIE2_MSG_PRIV_H_ */

View File

@@ -924,6 +924,9 @@ static int aie2_get_array(struct amdxdna_client *client,
case DRM_AMDXDNA_HW_CONTEXT_ALL:
ret = aie2_query_ctx_status_array(client, args);
break;
case DRM_AMDXDNA_HW_LAST_ASYNC_ERR:
ret = aie2_get_array_async_error(xdna->dev_handle, args);
break;
default:
XDNA_ERR(xdna, "Not supported request parameter %u", args->param);
ret = -EOPNOTSUPP;
@@ -1001,6 +1004,7 @@ const struct amdxdna_dev_ops aie2_ops = {
.hwctx_init = aie2_hwctx_init,
.hwctx_fini = aie2_hwctx_fini,
.hwctx_config = aie2_hwctx_config,
.hwctx_sync_debug_bo = aie2_hwctx_sync_debug_bo,
.cmd_submit = aie2_cmd_submit,
.hmm_invalidate = aie2_hmm_invalidate,
.get_array = aie2_get_array,

View File

@@ -190,6 +190,8 @@ struct amdxdna_dev_hdl {
enum aie2_dev_status dev_status;
u32 hwctx_num;
struct amdxdna_async_error last_async_err;
};
#define DEFINE_BAR_OFFSET(reg_name, bar, reg_addr) \
@@ -253,8 +255,9 @@ void aie2_psp_stop(struct psp_device *psp);
/* aie2_error.c */
int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev);
void aie2_error_async_events_free(struct amdxdna_dev_hdl *ndev);
int aie2_error_async_events_send(struct amdxdna_dev_hdl *ndev);
int aie2_error_async_msg_thread(void *data);
int aie2_get_array_async_error(struct amdxdna_dev_hdl *ndev,
struct amdxdna_drm_get_array *args);
/* aie2_message.c */
int aie2_suspend_fw(struct amdxdna_dev_hdl *ndev);
@@ -284,11 +287,14 @@ int aie2_cmdlist_multi_execbuf(struct amdxdna_hwctx *hwctx,
int (*notify_cb)(void *, void __iomem *, size_t));
int aie2_sync_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job,
int (*notify_cb)(void *, void __iomem *, size_t));
int aie2_config_debug_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job,
int (*notify_cb)(void *, void __iomem *, size_t));
/* aie2_hwctx.c */
int aie2_hwctx_init(struct amdxdna_hwctx *hwctx);
void aie2_hwctx_fini(struct amdxdna_hwctx *hwctx);
int aie2_hwctx_config(struct amdxdna_hwctx *hwctx, u32 type, u64 value, void *buf, u32 size);
int aie2_hwctx_sync_debug_bo(struct amdxdna_hwctx *hwctx, u32 debug_bo_hdl);
void aie2_hwctx_suspend(struct amdxdna_client *client);
int aie2_hwctx_resume(struct amdxdna_client *client);
int aie2_cmd_submit(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job, u64 *seq);

View File

@@ -328,6 +328,38 @@ unlock_srcu:
return ret;
}
int amdxdna_hwctx_sync_debug_bo(struct amdxdna_client *client, u32 debug_bo_hdl)
{
struct amdxdna_dev *xdna = client->xdna;
struct amdxdna_hwctx *hwctx;
struct amdxdna_gem_obj *abo;
struct drm_gem_object *gobj;
int ret, idx;
if (!xdna->dev_info->ops->hwctx_sync_debug_bo)
return -EOPNOTSUPP;
gobj = drm_gem_object_lookup(client->filp, debug_bo_hdl);
if (!gobj)
return -EINVAL;
abo = to_xdna_obj(gobj);
guard(mutex)(&xdna->dev_lock);
idx = srcu_read_lock(&client->hwctx_srcu);
hwctx = xa_load(&client->hwctx_xa, abo->assigned_hwctx);
if (!hwctx) {
ret = -EINVAL;
goto unlock_srcu;
}
ret = xdna->dev_info->ops->hwctx_sync_debug_bo(hwctx, debug_bo_hdl);
unlock_srcu:
srcu_read_unlock(&client->hwctx_srcu, idx);
drm_gem_object_put(gobj);
return ret;
}
static void
amdxdna_arg_bos_put(struct amdxdna_sched_job *job)
{
@@ -393,6 +425,7 @@ void amdxdna_sched_job_cleanup(struct amdxdna_sched_job *job)
}
int amdxdna_cmd_submit(struct amdxdna_client *client,
struct amdxdna_drv_cmd *drv_cmd,
u32 cmd_bo_hdl, u32 *arg_bo_hdls, u32 arg_bo_cnt,
u32 hwctx_hdl, u64 *seq)
{
@@ -406,6 +439,8 @@ int amdxdna_cmd_submit(struct amdxdna_client *client,
if (!job)
return -ENOMEM;
job->drv_cmd = drv_cmd;
if (cmd_bo_hdl != AMDXDNA_INVALID_BO_HANDLE) {
job->cmd_bo = amdxdna_gem_get_obj(client, cmd_bo_hdl, AMDXDNA_BO_CMD);
if (!job->cmd_bo) {
@@ -413,8 +448,6 @@ int amdxdna_cmd_submit(struct amdxdna_client *client,
ret = -EINVAL;
goto free_job;
}
} else {
job->cmd_bo = NULL;
}
ret = amdxdna_arg_bos_lookup(client, job, arg_bo_hdls, arg_bo_cnt);
@@ -508,7 +541,7 @@ static int amdxdna_drm_submit_execbuf(struct amdxdna_client *client,
}
}
ret = amdxdna_cmd_submit(client, cmd_bo_hdl, arg_bo_hdls,
ret = amdxdna_cmd_submit(client, NULL, cmd_bo_hdl, arg_bo_hdls,
args->arg_count, args->hwctx, &args->seq);
if (ret)
XDNA_DBG(xdna, "Submit cmds failed, ret %d", ret);

View File

@@ -95,6 +95,17 @@ struct amdxdna_hwctx {
#define drm_job_to_xdna_job(j) \
container_of(j, struct amdxdna_sched_job, base)
enum amdxdna_job_opcode {
SYNC_DEBUG_BO,
ATTACH_DEBUG_BO,
DETACH_DEBUG_BO,
};
struct amdxdna_drv_cmd {
enum amdxdna_job_opcode opcode;
u32 result;
};
struct amdxdna_sched_job {
struct drm_sched_job base;
struct kref refcnt;
@@ -106,6 +117,7 @@ struct amdxdna_sched_job {
struct dma_fence *out_fence;
bool job_done;
u64 seq;
struct amdxdna_drv_cmd *drv_cmd;
struct amdxdna_gem_obj *cmd_bo;
size_t bo_cnt;
struct drm_gem_object *bos[] __counted_by(bo_cnt);
@@ -143,9 +155,11 @@ void amdxdna_sched_job_cleanup(struct amdxdna_sched_job *job);
void amdxdna_hwctx_remove_all(struct amdxdna_client *client);
int amdxdna_hwctx_walk(struct amdxdna_client *client, void *arg,
int (*walk)(struct amdxdna_hwctx *hwctx, void *arg));
int amdxdna_hwctx_sync_debug_bo(struct amdxdna_client *client, u32 debug_bo_hdl);
int amdxdna_cmd_submit(struct amdxdna_client *client,
u32 cmd_bo_hdls, u32 *arg_bo_hdls, u32 arg_bo_cnt,
struct amdxdna_drv_cmd *drv_cmd, u32 cmd_bo_hdls,
u32 *arg_bo_hdls, u32 arg_bo_cnt,
u32 hwctx_hdl, u64 *seq);
int amdxdna_cmd_wait(struct amdxdna_client *client, u32 hwctx_hdl,

View File

@@ -0,0 +1,59 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2025, Advanced Micro Devices, Inc.
*/
#ifndef _AMDXDNA_ERROR_H_
#define _AMDXDNA_ERROR_H_
#include <linux/bitfield.h>
#include <linux/bits.h>
#define AMDXDNA_ERR_DRV_AIE 4
#define AMDXDNA_ERR_SEV_CRITICAL 3
#define AMDXDNA_ERR_CLASS_AIE 2
#define AMDXDNA_ERR_NUM_MASK GENMASK_U64(15, 0)
#define AMDXDNA_ERR_DRV_MASK GENMASK_U64(23, 16)
#define AMDXDNA_ERR_SEV_MASK GENMASK_U64(31, 24)
#define AMDXDNA_ERR_MOD_MASK GENMASK_U64(39, 32)
#define AMDXDNA_ERR_CLASS_MASK GENMASK_U64(47, 40)
enum amdxdna_error_num {
AMDXDNA_ERROR_NUM_AIE_SATURATION = 3,
AMDXDNA_ERROR_NUM_AIE_FP,
AMDXDNA_ERROR_NUM_AIE_STREAM,
AMDXDNA_ERROR_NUM_AIE_ACCESS,
AMDXDNA_ERROR_NUM_AIE_BUS,
AMDXDNA_ERROR_NUM_AIE_INSTRUCTION,
AMDXDNA_ERROR_NUM_AIE_ECC,
AMDXDNA_ERROR_NUM_AIE_LOCK,
AMDXDNA_ERROR_NUM_AIE_DMA,
AMDXDNA_ERROR_NUM_AIE_MEM_PARITY,
AMDXDNA_ERROR_NUM_UNKNOWN = 15,
};
enum amdxdna_error_module {
AMDXDNA_ERROR_MODULE_AIE_CORE = 3,
AMDXDNA_ERROR_MODULE_AIE_MEMORY,
AMDXDNA_ERROR_MODULE_AIE_SHIM,
AMDXDNA_ERROR_MODULE_AIE_NOC,
AMDXDNA_ERROR_MODULE_AIE_PL,
AMDXDNA_ERROR_MODULE_UNKNOWN = 8,
};
#define AMDXDNA_ERROR_ENCODE(err_num, err_mod) \
(FIELD_PREP(AMDXDNA_ERR_NUM_MASK, err_num) | \
FIELD_PREP_CONST(AMDXDNA_ERR_DRV_MASK, AMDXDNA_ERR_DRV_AIE) | \
FIELD_PREP_CONST(AMDXDNA_ERR_SEV_MASK, AMDXDNA_ERR_SEV_CRITICAL) | \
FIELD_PREP(AMDXDNA_ERR_MOD_MASK, err_mod) | \
FIELD_PREP_CONST(AMDXDNA_ERR_CLASS_MASK, AMDXDNA_ERR_CLASS_AIE))
#define AMDXDNA_EXTRA_ERR_COL_MASK GENMASK_U64(7, 0)
#define AMDXDNA_EXTRA_ERR_ROW_MASK GENMASK_U64(15, 8)
#define AMDXDNA_EXTRA_ERR_ENCODE(row, col) \
(FIELD_PREP(AMDXDNA_EXTRA_ERR_COL_MASK, col) | \
FIELD_PREP(AMDXDNA_EXTRA_ERR_ROW_MASK, row))
#endif /* _AMDXDNA_ERROR_H_ */

View File

@@ -962,6 +962,9 @@ int amdxdna_drm_sync_bo_ioctl(struct drm_device *dev,
XDNA_DBG(xdna, "Sync bo %d offset 0x%llx, size 0x%llx\n",
args->handle, args->offset, args->size);
if (args->direction == SYNC_DIRECT_FROM_DEVICE)
ret = amdxdna_hwctx_sync_debug_bo(abo->client, args->handle);
put_obj:
drm_gem_object_put(gobj);
return ret;

View File

@@ -7,6 +7,7 @@
#define _AMDXDNA_GEM_H_
#include <linux/hmm.h>
#include "amdxdna_pci_drv.h"
struct amdxdna_umap {
struct vm_area_struct *vma;
@@ -62,6 +63,11 @@ static inline void amdxdna_gem_put_obj(struct amdxdna_gem_obj *abo)
drm_gem_object_put(to_gobj(abo));
}
static inline u64 amdxdna_dev_bo_offset(struct amdxdna_gem_obj *abo)
{
return abo->mem.dev_addr - abo->client->dev_heap->mem.dev_addr;
}
void amdxdna_umap_put(struct amdxdna_umap *mapp);
struct drm_gem_object *

View File

@@ -27,9 +27,11 @@ MODULE_FIRMWARE("amdnpu/17f0_20/npu.sbin");
/*
* 0.0: Initial version
* 0.1: Support getting all hardware contexts by DRM_IOCTL_AMDXDNA_GET_ARRAY
* 0.2: Support getting last error hardware error
* 0.3: Support firmware debug buffer
*/
#define AMDXDNA_DRIVER_MAJOR 0
#define AMDXDNA_DRIVER_MINOR 1
#define AMDXDNA_DRIVER_MINOR 3
/*
* Bind the driver base on (vendor_id, device_id) pair and later use the

View File

@@ -55,6 +55,7 @@ struct amdxdna_dev_ops {
int (*hwctx_init)(struct amdxdna_hwctx *hwctx);
void (*hwctx_fini)(struct amdxdna_hwctx *hwctx);
int (*hwctx_config)(struct amdxdna_hwctx *hwctx, u32 type, u64 value, void *buf, u32 size);
int (*hwctx_sync_debug_bo)(struct amdxdna_hwctx *hwctx, u32 debug_bo_hdl);
void (*hmm_invalidate)(struct amdxdna_gem_obj *abo, unsigned long cur_seq);
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);

View File

@@ -46,6 +46,7 @@
const struct rt_config npu1_default_rt_cfg[] = {
{ 2, 1, AIE2_RT_CFG_INIT }, /* PDI APP LOAD MODE */
{ 4, 1, AIE2_RT_CFG_INIT }, /* Debug BO */
{ 1, 1, AIE2_RT_CFG_CLK_GATING }, /* Clock gating on */
{ 0 },
};

View File

@@ -63,6 +63,7 @@
const struct rt_config npu4_default_rt_cfg[] = {
{ 5, 1, AIE2_RT_CFG_INIT }, /* PDI APP LOAD MODE */
{ 10, 1, AIE2_RT_CFG_INIT }, /* DEBUG BUF */
{ 1, 1, AIE2_RT_CFG_CLK_GATING }, /* Clock gating on */
{ 2, 1, AIE2_RT_CFG_CLK_GATING }, /* Clock gating on */
{ 3, 1, AIE2_RT_CFG_CLK_GATING }, /* Clock gating on */

View File

@@ -46,12 +46,13 @@ static inline void ivpu_bo_unlock(struct ivpu_bo *bo)
static struct sg_table *ivpu_bo_map_attachment(struct ivpu_device *vdev, struct ivpu_bo *bo)
{
struct sg_table *sgt = bo->base.sgt;
struct sg_table *sgt;
drm_WARN_ON(&vdev->drm, !bo->base.base.import_attach);
ivpu_bo_lock(bo);
sgt = bo->base.sgt;
if (!sgt) {
sgt = dma_buf_map_attachment(bo->base.base.import_attach, DMA_BIDIRECTIONAL);
if (IS_ERR(sgt))

View File

@@ -564,6 +564,44 @@ static struct ivpu_job *ivpu_job_remove_from_submitted_jobs(struct ivpu_device *
return job;
}
bool ivpu_job_handle_engine_error(struct ivpu_device *vdev, u32 job_id, u32 job_status)
{
lockdep_assert_held(&vdev->submitted_jobs_lock);
switch (job_status) {
case VPU_JSM_STATUS_PROCESSING_ERR:
case VPU_JSM_STATUS_ENGINE_RESET_REQUIRED_MIN ... VPU_JSM_STATUS_ENGINE_RESET_REQUIRED_MAX:
{
struct ivpu_job *job = xa_load(&vdev->submitted_jobs_xa, job_id);
if (!job)
return false;
/* Trigger an engine reset */
guard(mutex)(&job->file_priv->lock);
job->job_status = job_status;
if (job->file_priv->has_mmu_faults)
return false;
/*
* Mark context as faulty and defer destruction of the job to jobs abort thread
* handler to synchronize between both faults and jobs returning context violation
* status and ensure both are handled in the same way
*/
job->file_priv->has_mmu_faults = true;
queue_work(system_wq, &vdev->context_abort_work);
return true;
}
default:
/* Complete job with error status, engine reset not required */
break;
}
return false;
}
static int ivpu_job_signal_and_destroy(struct ivpu_device *vdev, u32 job_id, u32 job_status)
{
struct ivpu_job *job;
@@ -574,35 +612,22 @@ static int ivpu_job_signal_and_destroy(struct ivpu_device *vdev, u32 job_id, u32
if (!job)
return -ENOENT;
if (job_status == VPU_JSM_STATUS_MVNCI_CONTEXT_VIOLATION_HW) {
guard(mutex)(&job->file_priv->lock);
ivpu_job_remove_from_submitted_jobs(vdev, job_id);
if (job->job_status == VPU_JSM_STATUS_SUCCESS) {
if (job->file_priv->has_mmu_faults)
return 0;
/*
* Mark context as faulty and defer destruction of the job to jobs abort thread
* handler to synchronize between both faults and jobs returning context violation
* status and ensure both are handled in the same way
*/
job->file_priv->has_mmu_faults = true;
queue_work(system_wq, &vdev->context_abort_work);
return 0;
job->job_status = DRM_IVPU_JOB_STATUS_ABORTED;
else
job->job_status = job_status;
}
job = ivpu_job_remove_from_submitted_jobs(vdev, job_id);
if (!job)
return -ENOENT;
if (job->file_priv->has_mmu_faults)
job_status = DRM_IVPU_JOB_STATUS_ABORTED;
job->bos[CMD_BUF_IDX]->job_status = job_status;
job->bos[CMD_BUF_IDX]->job_status = job->job_status;
dma_fence_signal(job->done_fence);
trace_job("done", job);
ivpu_dbg(vdev, JOB, "Job complete: id %3u ctx %2d cmdq_id %u engine %d status 0x%x\n",
job->job_id, job->file_priv->ctx.id, job->cmdq_id, job->engine_idx, job_status);
job->job_id, job->file_priv->ctx.id, job->cmdq_id, job->engine_idx,
job->job_status);
ivpu_job_destroy(job);
ivpu_stop_job_timeout_detection(vdev);
@@ -1022,7 +1047,9 @@ ivpu_job_done_callback(struct ivpu_device *vdev, struct ivpu_ipc_hdr *ipc_hdr,
payload = (struct vpu_ipc_msg_payload_job_done *)&jsm_msg->payload;
mutex_lock(&vdev->submitted_jobs_lock);
ivpu_job_signal_and_destroy(vdev, payload->job_id, payload->job_status);
if (!ivpu_job_handle_engine_error(vdev, payload->job_id, payload->job_status))
/* No engine error, complete the job normally */
ivpu_job_signal_and_destroy(vdev, payload->job_id, payload->job_status);
mutex_unlock(&vdev->submitted_jobs_lock);
}

View File

@@ -51,6 +51,7 @@ struct ivpu_cmdq {
* @cmdq_id: Command queue ID used for submission
* @job_id: Unique job ID for tracking and status reporting
* @engine_idx: Engine index for job execution
* @job_status: Status reported by firmware for this job
* @primary_preempt_buf: Primary preemption buffer for job
* @secondary_preempt_buf: Secondary preemption buffer for job (optional)
* @bo_count: Number of buffer objects associated with this job
@@ -64,6 +65,7 @@ struct ivpu_job {
u32 cmdq_id;
u32 job_id;
u32 engine_idx;
u32 job_status;
struct ivpu_bo *primary_preempt_buf;
struct ivpu_bo *secondary_preempt_buf;
size_t bo_count;
@@ -83,6 +85,7 @@ void ivpu_cmdq_abort_all_jobs(struct ivpu_device *vdev, u32 ctx_id, u32 cmdq_id)
void ivpu_job_done_consumer_init(struct ivpu_device *vdev);
void ivpu_job_done_consumer_fini(struct ivpu_device *vdev);
bool ivpu_job_handle_engine_error(struct ivpu_device *vdev, u32 job_id, u32 job_status);
void ivpu_context_abort_work_fn(struct work_struct *work);
void ivpu_jobs_abort_all(struct ivpu_device *vdev);

View File

@@ -23,12 +23,12 @@
/*
* Minor version changes when API backward compatibility is preserved.
*/
#define VPU_JSM_API_VER_MINOR 32
#define VPU_JSM_API_VER_MINOR 33
/*
* API header changed (field names, documentation, formatting) but API itself has not been changed
*/
#define VPU_JSM_API_VER_PATCH 5
#define VPU_JSM_API_VER_PATCH 0
/*
* Index in the API version table
@@ -76,8 +76,11 @@
#define VPU_JSM_STATUS_PREEMPTED_MID_INFERENCE 0xDU
/* Job status returned when the job was preempted mid-command */
#define VPU_JSM_STATUS_PREEMPTED_MID_COMMAND 0xDU
/* Range of status codes that require engine reset */
#define VPU_JSM_STATUS_ENGINE_RESET_REQUIRED_MIN 0xEU
#define VPU_JSM_STATUS_MVNCI_CONTEXT_VIOLATION_HW 0xEU
#define VPU_JSM_STATUS_MVNCI_PREEMPTION_TIMED_OUT 0xFU
#define VPU_JSM_STATUS_ENGINE_RESET_REQUIRED_MAX 0x1FU
/*
* Host <-> VPU IPC channels.
@@ -404,8 +407,8 @@ struct vpu_hws_native_fence_log_header {
/** Index of the first free entry in buffer. */
u32 first_free_entry_idx;
/**
* Incremented each time NPU wraps around
* the buffer to write next entry.
* Incremented whenever the NPU wraps around the buffer and writes
* to the first entry again.
*/
u32 wraparound_count;
};
@@ -454,10 +457,17 @@ struct vpu_hws_native_fence_log_buffer {
* Host <-> VPU IPC messages types.
*/
enum vpu_ipc_msg_type {
/** Unsupported command */
VPU_JSM_MSG_UNKNOWN = 0xFFFFFFFF,
/* IPC Host -> Device, Async commands */
/** IPC Host -> Device, base id for async commands */
VPU_JSM_MSG_ASYNC_CMD = 0x1100,
/**
* Reset engine. The NPU cancels all the jobs currently executing on the target
* engine making the engine become idle and then does a HW reset, before returning
* to the host.
* @see struct vpu_ipc_msg_payload_engine_reset
*/
VPU_JSM_MSG_ENGINE_RESET = VPU_JSM_MSG_ASYNC_CMD,
/**
* Preempt engine. The NPU stops (preempts) all the jobs currently
@@ -467,6 +477,7 @@ enum vpu_ipc_msg_type {
* the target engine, but it stops processing them (until the queue doorbell
* is rung again); the host is responsible to reset the job queue, either
* after preemption or when resubmitting jobs to the queue.
* @see vpu_ipc_msg_payload_engine_preempt
*/
VPU_JSM_MSG_ENGINE_PREEMPT = 0x1101,
/**
@@ -583,23 +594,32 @@ enum vpu_ipc_msg_type {
* @see vpu_ipc_msg_payload_hws_resume_engine
*/
VPU_JSM_MSG_HWS_ENGINE_RESUME = 0x111b,
/* Control command: Enable survivability/DCT mode */
/**
* Control command: Enable survivability/DCT mode
* @see vpu_ipc_msg_payload_pwr_dct_control
*/
VPU_JSM_MSG_DCT_ENABLE = 0x111c,
/* Control command: Disable survivability/DCT mode */
/**
* Control command: Disable survivability/DCT mode
* This command has no payload
*/
VPU_JSM_MSG_DCT_DISABLE = 0x111d,
/**
* Dump VPU state. To be used for debug purposes only.
* NOTE: Please introduce new ASYNC commands before this one. *
* This command has no payload.
* NOTE: Please introduce new ASYNC commands before this one.
*/
VPU_JSM_MSG_STATE_DUMP = 0x11FF,
/* IPC Host -> Device, General commands */
/** IPC Host -> Device, base id for general commands */
VPU_JSM_MSG_GENERAL_CMD = 0x1200,
/** Unsupported command */
VPU_JSM_MSG_BLOB_DEINIT_DEPRECATED = VPU_JSM_MSG_GENERAL_CMD,
/**
* Control dyndbg behavior by executing a dyndbg command; equivalent to
* Linux command:
* @verbatim echo '<dyndbg_cmd>' > <debugfs>/dynamic_debug/control @endverbatim
* @see vpu_ipc_msg_payload_dyndbg_control
*/
VPU_JSM_MSG_DYNDBG_CONTROL = 0x1201,
/**
@@ -607,7 +627,10 @@ enum vpu_ipc_msg_type {
*/
VPU_JSM_MSG_PWR_D0I3_ENTER = 0x1202,
/* IPC Device -> Host, Job completion */
/**
* IPC Device -> Host, Job completion
* @see struct vpu_ipc_msg_payload_job_done
*/
VPU_JSM_MSG_JOB_DONE = 0x2100,
/**
* IPC Device -> Host, Fence signalled
@@ -622,6 +645,10 @@ enum vpu_ipc_msg_type {
* @see vpu_ipc_msg_payload_engine_reset_done
*/
VPU_JSM_MSG_ENGINE_RESET_DONE = VPU_JSM_MSG_ASYNC_CMD_DONE,
/**
* Preempt complete message
* @see vpu_ipc_msg_payload_engine_preempt_done
*/
VPU_JSM_MSG_ENGINE_PREEMPT_DONE = 0x2201,
VPU_JSM_MSG_REGISTER_DB_DONE = 0x2202,
VPU_JSM_MSG_UNREGISTER_DB_DONE = 0x2203,
@@ -729,13 +756,20 @@ enum vpu_ipc_msg_type {
* @see vpu_ipc_msg_payload_hws_resume_engine
*/
VPU_JSM_MSG_HWS_RESUME_ENGINE_DONE = 0x221c,
/* Response to control command: Enable survivability/DCT mode */
/**
* Response to control command: Enable survivability/DCT mode
* This command has no payload
*/
VPU_JSM_MSG_DCT_ENABLE_DONE = 0x221d,
/* Response to control command: Disable survivability/DCT mode */
/**
* Response to control command: Disable survivability/DCT mode
* This command has no payload
*/
VPU_JSM_MSG_DCT_DISABLE_DONE = 0x221e,
/**
* Response to state dump control command.
* NOTE: Please introduce new ASYNC responses before this one. *
* This command has no payload.
* NOTE: Please introduce new ASYNC responses before this one.
*/
VPU_JSM_MSG_STATE_DUMP_RSP = 0x22FF,
@@ -753,20 +787,25 @@ enum vpu_ipc_msg_type {
enum vpu_ipc_msg_status { VPU_JSM_MSG_FREE, VPU_JSM_MSG_ALLOCATED };
/*
* Host <-> LRT IPC message payload definitions
/**
* Engine reset request payload
* @see VPU_JSM_MSG_ENGINE_RESET
*/
struct vpu_ipc_msg_payload_engine_reset {
/* Engine to be reset. */
/** Engine to be reset. */
u32 engine_idx;
/* Reserved */
/** Reserved */
u32 reserved_0;
};
/**
* Engine preemption request struct
* @see VPU_JSM_MSG_ENGINE_PREEMPT
*/
struct vpu_ipc_msg_payload_engine_preempt {
/* Engine to be preempted. */
/** Engine to be preempted. */
u32 engine_idx;
/* ID of the preemption request. */
/** ID of the preemption request. */
u32 preempt_id;
};
@@ -935,20 +974,24 @@ struct vpu_jsm_metric_streamer_update {
u64 next_buffer_size;
};
/**
* Device -> host job completion message.
* @see VPU_JSM_MSG_JOB_DONE
*/
struct vpu_ipc_msg_payload_job_done {
/* Engine to which the job was submitted. */
/** Engine to which the job was submitted. */
u32 engine_idx;
/* Index of the doorbell to which the job was submitted */
/** Index of the doorbell to which the job was submitted */
u32 db_idx;
/* ID of the completed job */
/** ID of the completed job */
u32 job_id;
/* Status of the completed job */
/** Status of the completed job */
u32 job_status;
/* Host SSID */
/** Host SSID */
u32 host_ssid;
/* Zero Padding */
/** Zero Padding */
u32 reserved_0;
/* Command queue id */
/** Command queue id */
u64 cmdq_id;
};
@@ -997,10 +1040,14 @@ struct vpu_ipc_msg_payload_engine_reset_done {
impacted_contexts[VPU_MAX_ENGINE_RESET_IMPACTED_CONTEXTS];
};
/**
* Preemption response struct
* @see VPU_JSM_MSG_ENGINE_PREEMPT_DONE
*/
struct vpu_ipc_msg_payload_engine_preempt_done {
/* Engine preempted. */
/** Engine preempted. */
u32 engine_idx;
/* ID of the preemption request. */
/** ID of the preemption request. */
u32 preempt_id;
};
@@ -1552,29 +1599,24 @@ struct vpu_jsm_metric_counter_descriptor {
};
/**
* Payload for VPU_JSM_MSG_DYNDBG_CONTROL requests.
* Payload for @ref VPU_JSM_MSG_DYNDBG_CONTROL requests.
*
* VPU_JSM_MSG_DYNDBG_CONTROL are used to control the VPU FW Dynamic Debug
* feature, which allows developers to selectively enable / disable MVLOG_DEBUG
* messages. This is equivalent to the Dynamic Debug functionality provided by
* Linux
* (https://www.kernel.org/doc/html/latest/admin-guide/dynamic-debug-howto.html)
* The host can control Dynamic Debug behavior by sending dyndbg commands, which
* have the same syntax as Linux
* dyndbg commands.
* VPU_JSM_MSG_DYNDBG_CONTROL requests are used to control the VPU FW dynamic debug
* feature, which allows developers to selectively enable/disable code to obtain
* additional FW information. This is equivalent to the dynamic debug functionality
* provided by Linux. The host can control dynamic debug behavior by sending dyndbg
* commands, using the same syntax as for Linux dynamic debug commands.
*
* NOTE: in order for MVLOG_DEBUG messages to be actually printed, the host
* still has to set the logging level to MVLOG_DEBUG, using the
* VPU_JSM_MSG_TRACE_SET_CONFIG command.
* @see https://www.kernel.org/doc/html/latest/admin-guide/dynamic-debug-howto.html.
*
* The host can see the current dynamic debug configuration by executing a
* special 'show' command. The dyndbg configuration will be printed to the
* configured logging destination using MVLOG_INFO logging level.
* NOTE:
* As the dynamic debug feature uses MVLOG messages to provide information, the host
* must first set the logging level to MVLOG_DEBUG, using the @ref VPU_JSM_MSG_TRACE_SET_CONFIG
* command.
*/
struct vpu_ipc_msg_payload_dyndbg_control {
/**
* Dyndbg command (same format as Linux dyndbg); must be a NULL-terminated
* string.
* Dyndbg command to be executed.
*/
char dyndbg_cmd[VPU_DYNDBG_CMD_MAX_LEN];
};
@@ -1595,7 +1637,7 @@ struct vpu_ipc_msg_payload_pwr_d0i3_enter {
};
/**
* Payload for VPU_JSM_MSG_DCT_ENABLE message.
* Payload for @ref VPU_JSM_MSG_DCT_ENABLE message.
*
* Default values for DCT active/inactive times are 5.3ms and 30ms respectively,
* corresponding to a 85% duty cycle. This payload allows the host to tune these
@@ -1652,28 +1694,28 @@ union vpu_ipc_msg_payload {
struct vpu_ipc_msg_payload_pwr_dct_control pwr_dct_control;
};
/*
* Host <-> LRT IPC message base structure.
/**
* Host <-> NPU IPC message base structure.
*
* NOTE: All instances of this object must be aligned on a 64B boundary
* to allow proper handling of VPU cache operations.
*/
struct vpu_jsm_msg {
/* Reserved */
/** Reserved */
u64 reserved_0;
/* Message type, see vpu_ipc_msg_type enum. */
/** Message type, see @ref vpu_ipc_msg_type. */
u32 type;
/* Buffer status, see vpu_ipc_msg_status enum. */
/** Buffer status, see @ref vpu_ipc_msg_status. */
u32 status;
/*
/**
* Request ID, provided by the host in a request message and passed
* back by VPU in the response message.
*/
u32 request_id;
/* Request return code set by the VPU, see VPU_JSM_STATUS_* defines. */
/** Request return code set by the VPU, see VPU_JSM_STATUS_* defines. */
u32 result;
u64 reserved_1;
/* Message payload depending on message type, see vpu_ipc_msg_payload union. */
/** Message payload depending on message type, see vpu_ipc_msg_payload union. */
union vpu_ipc_msg_payload payload;
};

View File

@@ -17,6 +17,7 @@
#include <linux/overflow.h>
#include <linux/pci.h>
#include <linux/scatterlist.h>
#include <linux/sched/signal.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/workqueue.h>
@@ -655,8 +656,9 @@ static int encode_activate(struct qaic_device *qdev, void *trans, struct wrapper
return -EINVAL;
nelem = in_trans->queue_size;
size = (get_dbc_req_elem_size() + get_dbc_rsp_elem_size()) * nelem;
if (size / nelem != get_dbc_req_elem_size() + get_dbc_rsp_elem_size())
if (check_mul_overflow((u32)(get_dbc_req_elem_size() + get_dbc_rsp_elem_size()),
nelem,
&size))
return -EINVAL;
if (size + QAIC_DBC_Q_GAP + QAIC_DBC_Q_BUF_ALIGN < size)
@@ -810,7 +812,7 @@ static int encode_message(struct qaic_device *qdev, struct manage_msg *user_msg,
}
if (ret)
break;
goto out;
}
if (user_len != user_msg->len)
@@ -1079,7 +1081,6 @@ static void *msg_xfer(struct qaic_device *qdev, struct wrapper_list *wrappers, u
list_for_each_entry(w, &wrappers->list, list) {
kref_get(&w->ref_count);
retry_count = 0;
ret = mhi_queue_buf(qdev->cntl_ch, DMA_TO_DEVICE, &w->msg, w->len,
list_is_last(&w->list, &wrappers->list) ? MHI_EOT : MHI_CHAIN);
if (ret) {

View File

@@ -18,6 +18,7 @@
#include <linux/scatterlist.h>
#include <linux/spinlock.h>
#include <linux/srcu.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/wait.h>
@@ -165,7 +166,7 @@ static void free_slice(struct kref *kref)
drm_gem_object_put(&slice->bo->base);
sg_free_table(slice->sgt);
kfree(slice->sgt);
kfree(slice->reqs);
kvfree(slice->reqs);
kfree(slice);
}
@@ -404,7 +405,7 @@ static int qaic_map_one_slice(struct qaic_device *qdev, struct qaic_bo *bo,
goto free_sgt;
}
slice->reqs = kcalloc(sgt->nents, sizeof(*slice->reqs), GFP_KERNEL);
slice->reqs = kvcalloc(sgt->nents, sizeof(*slice->reqs), GFP_KERNEL);
if (!slice->reqs) {
ret = -ENOMEM;
goto free_slice;
@@ -430,7 +431,7 @@ static int qaic_map_one_slice(struct qaic_device *qdev, struct qaic_bo *bo,
return 0;
free_req:
kfree(slice->reqs);
kvfree(slice->reqs);
free_slice:
kfree(slice);
free_sgt:
@@ -643,8 +644,36 @@ static void qaic_free_object(struct drm_gem_object *obj)
kfree(bo);
}
static struct sg_table *qaic_get_sg_table(struct drm_gem_object *obj)
{
struct qaic_bo *bo = to_qaic_bo(obj);
struct scatterlist *sg, *sg_in;
struct sg_table *sgt, *sgt_in;
int i;
sgt_in = bo->sgt;
sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
if (!sgt)
return ERR_PTR(-ENOMEM);
if (sg_alloc_table(sgt, sgt_in->orig_nents, GFP_KERNEL)) {
kfree(sgt);
return ERR_PTR(-ENOMEM);
}
sg = sgt->sgl;
for_each_sgtable_sg(sgt_in, sg_in, i) {
memcpy(sg, sg_in, sizeof(*sg));
sg = sg_next(sg);
}
return sgt;
}
static const struct drm_gem_object_funcs qaic_gem_funcs = {
.free = qaic_free_object,
.get_sg_table = qaic_get_sg_table,
.print_info = qaic_gem_print_info,
.mmap = qaic_gem_object_mmap,
.vm_ops = &drm_vm_ops,
@@ -953,8 +982,9 @@ int qaic_attach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi
if (args->hdr.count == 0)
return -EINVAL;
arg_size = args->hdr.count * sizeof(*slice_ent);
if (arg_size / args->hdr.count != sizeof(*slice_ent))
if (check_mul_overflow((unsigned long)args->hdr.count,
(unsigned long)sizeof(*slice_ent),
&arg_size))
return -EINVAL;
if (!(args->hdr.dir == DMA_TO_DEVICE || args->hdr.dir == DMA_FROM_DEVICE))
@@ -984,18 +1014,12 @@ int qaic_attach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi
user_data = u64_to_user_ptr(args->data);
slice_ent = kzalloc(arg_size, GFP_KERNEL);
if (!slice_ent) {
ret = -EINVAL;
slice_ent = memdup_user(user_data, arg_size);
if (IS_ERR(slice_ent)) {
ret = PTR_ERR(slice_ent);
goto unlock_dev_srcu;
}
ret = copy_from_user(slice_ent, user_data, arg_size);
if (ret) {
ret = -EFAULT;
goto free_slice_ent;
}
obj = drm_gem_object_lookup(file_priv, args->hdr.handle);
if (!obj) {
ret = -ENOENT;
@@ -1300,8 +1324,6 @@ static int __qaic_execute_bo_ioctl(struct drm_device *dev, void *data, struct dr
int usr_rcu_id, qdev_rcu_id;
struct qaic_device *qdev;
struct qaic_user *usr;
u8 __user *user_data;
unsigned long n;
u64 received_ts;
u32 queue_level;
u64 submit_ts;
@@ -1314,20 +1336,12 @@ static int __qaic_execute_bo_ioctl(struct drm_device *dev, void *data, struct dr
received_ts = ktime_get_ns();
size = is_partial ? sizeof(struct qaic_partial_execute_entry) : sizeof(*exec);
n = (unsigned long)size * args->hdr.count;
if (args->hdr.count == 0 || n / args->hdr.count != size)
if (args->hdr.count == 0)
return -EINVAL;
user_data = u64_to_user_ptr(args->data);
exec = kcalloc(args->hdr.count, size, GFP_KERNEL);
if (!exec)
return -ENOMEM;
if (copy_from_user(exec, user_data, n)) {
ret = -EFAULT;
goto free_exec;
}
exec = memdup_array_user(u64_to_user_ptr(args->data), args->hdr.count, size);
if (IS_ERR(exec))
return PTR_ERR(exec);
usr = file_priv->driver_priv;
usr_rcu_id = srcu_read_lock(&usr->qddev_lock);
@@ -1396,7 +1410,6 @@ unlock_dev_srcu:
srcu_read_unlock(&qdev->dev_lock, qdev_rcu_id);
unlock_usr_srcu:
srcu_read_unlock(&usr->qddev_lock, usr_rcu_id);
free_exec:
kfree(exec);
return ret;
}
@@ -1749,7 +1762,8 @@ int qaic_perf_stats_bo_ioctl(struct drm_device *dev, void *data, struct drm_file
struct qaic_device *qdev;
struct qaic_user *usr;
struct qaic_bo *bo;
int ret, i;
int ret = 0;
int i;
usr = file_priv->driver_priv;
usr_rcu_id = srcu_read_lock(&usr->qddev_lock);
@@ -1770,18 +1784,12 @@ int qaic_perf_stats_bo_ioctl(struct drm_device *dev, void *data, struct drm_file
goto unlock_dev_srcu;
}
ent = kcalloc(args->hdr.count, sizeof(*ent), GFP_KERNEL);
if (!ent) {
ret = -EINVAL;
ent = memdup_array_user(u64_to_user_ptr(args->data), args->hdr.count, sizeof(*ent));
if (IS_ERR(ent)) {
ret = PTR_ERR(ent);
goto unlock_dev_srcu;
}
ret = copy_from_user(ent, u64_to_user_ptr(args->data), args->hdr.count * sizeof(*ent));
if (ret) {
ret = -EFAULT;
goto free_ent;
}
for (i = 0; i < args->hdr.count; i++) {
obj = drm_gem_object_lookup(file_priv, ent[i].handle);
if (!obj) {
@@ -1789,6 +1797,16 @@ int qaic_perf_stats_bo_ioctl(struct drm_device *dev, void *data, struct drm_file
goto free_ent;
}
bo = to_qaic_bo(obj);
if (!bo->sliced) {
drm_gem_object_put(obj);
ret = -EINVAL;
goto free_ent;
}
if (bo->dbc->id != args->hdr.dbc_id) {
drm_gem_object_put(obj);
ret = -EINVAL;
goto free_ent;
}
/*
* perf stats ioctl is called before wait ioctl is complete then
* the latency information is invalid.

View File

@@ -514,21 +514,21 @@ static ssize_t ce_count_show(struct device *dev, struct device_attribute *attr,
{
struct qaic_device *qdev = pci_get_drvdata(to_pci_dev(dev));
return snprintf(buf, PAGE_SIZE, "%d\n", qdev->ce_count);
return sysfs_emit(buf, "%d\n", qdev->ce_count);
}
static ssize_t ue_count_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct qaic_device *qdev = pci_get_drvdata(to_pci_dev(dev));
return snprintf(buf, PAGE_SIZE, "%d\n", qdev->ue_count);
return sysfs_emit(buf, "%d\n", qdev->ue_count);
}
static ssize_t ue_nonfatal_count_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct qaic_device *qdev = pci_get_drvdata(to_pci_dev(dev));
return snprintf(buf, PAGE_SIZE, "%d\n", qdev->ue_nf_count);
return sysfs_emit(buf, "%d\n", qdev->ue_nf_count);
}
static DEVICE_ATTR_RO(ce_count);

View File

@@ -159,6 +159,7 @@ struct sahara_context {
struct sahara_packet *rx;
struct work_struct fw_work;
struct work_struct dump_work;
struct work_struct read_data_work;
struct mhi_device *mhi_dev;
const char * const *image_table;
u32 table_size;
@@ -174,7 +175,10 @@ struct sahara_context {
u64 dump_image_offset;
void *mem_dump_freespace;
u64 dump_images_left;
u32 read_data_offset;
u32 read_data_length;
bool is_mem_dump_mode;
bool non_streaming;
};
static const char * const aic100_image_table[] = {
@@ -216,6 +220,11 @@ static const char * const aic200_image_table[] = {
[75] = "qcom/aic200/pvs.bin",
};
static bool is_streaming(struct sahara_context *context)
{
return !context->non_streaming;
}
static int sahara_find_image(struct sahara_context *context, u32 image_id)
{
int ret;
@@ -265,6 +274,8 @@ static void sahara_send_reset(struct sahara_context *context)
int ret;
context->is_mem_dump_mode = false;
context->read_data_offset = 0;
context->read_data_length = 0;
context->tx[0]->cmd = cpu_to_le32(SAHARA_RESET_CMD);
context->tx[0]->length = cpu_to_le32(SAHARA_RESET_LENGTH);
@@ -319,9 +330,39 @@ static void sahara_hello(struct sahara_context *context)
dev_err(&context->mhi_dev->dev, "Unable to send hello response %d\n", ret);
}
static int read_data_helper(struct sahara_context *context, int buf_index)
{
enum mhi_flags mhi_flag;
u32 pkt_data_len;
int ret;
pkt_data_len = min(context->read_data_length, SAHARA_PACKET_MAX_SIZE);
memcpy(context->tx[buf_index],
&context->firmware->data[context->read_data_offset],
pkt_data_len);
context->read_data_offset += pkt_data_len;
context->read_data_length -= pkt_data_len;
if (is_streaming(context) || !context->read_data_length)
mhi_flag = MHI_EOT;
else
mhi_flag = MHI_CHAIN;
ret = mhi_queue_buf(context->mhi_dev, DMA_TO_DEVICE,
context->tx[buf_index], pkt_data_len, mhi_flag);
if (ret) {
dev_err(&context->mhi_dev->dev, "Unable to send read_data response %d\n", ret);
return ret;
}
return 0;
}
static void sahara_read_data(struct sahara_context *context)
{
u32 image_id, data_offset, data_len, pkt_data_len;
u32 image_id, data_offset, data_len;
int ret;
int i;
@@ -357,7 +398,7 @@ static void sahara_read_data(struct sahara_context *context)
* and is not needed here on error.
*/
if (data_len > SAHARA_TRANSFER_MAX_SIZE) {
if (context->non_streaming && data_len > SAHARA_TRANSFER_MAX_SIZE) {
dev_err(&context->mhi_dev->dev, "Malformed read_data packet - data len %d exceeds max xfer size %d\n",
data_len, SAHARA_TRANSFER_MAX_SIZE);
sahara_send_reset(context);
@@ -378,22 +419,18 @@ static void sahara_read_data(struct sahara_context *context)
return;
}
for (i = 0; i < SAHARA_NUM_TX_BUF && data_len; ++i) {
pkt_data_len = min(data_len, SAHARA_PACKET_MAX_SIZE);
context->read_data_offset = data_offset;
context->read_data_length = data_len;
memcpy(context->tx[i], &context->firmware->data[data_offset], pkt_data_len);
if (is_streaming(context)) {
schedule_work(&context->read_data_work);
return;
}
data_offset += pkt_data_len;
data_len -= pkt_data_len;
ret = mhi_queue_buf(context->mhi_dev, DMA_TO_DEVICE,
context->tx[i], pkt_data_len,
!data_len ? MHI_EOT : MHI_CHAIN);
if (ret) {
dev_err(&context->mhi_dev->dev, "Unable to send read_data response %d\n",
ret);
return;
}
for (i = 0; i < SAHARA_NUM_TX_BUF && context->read_data_length; ++i) {
ret = read_data_helper(context, i);
if (ret)
break;
}
}
@@ -538,6 +575,7 @@ static void sahara_parse_dump_table(struct sahara_context *context)
struct sahara_memory_dump_meta_v1 *dump_meta;
u64 table_nents;
u64 dump_length;
u64 mul_bytes;
int ret;
u64 i;
@@ -551,8 +589,9 @@ static void sahara_parse_dump_table(struct sahara_context *context)
dev_table[i].description[SAHARA_TABLE_ENTRY_STR_LEN - 1] = 0;
dev_table[i].filename[SAHARA_TABLE_ENTRY_STR_LEN - 1] = 0;
dump_length = size_add(dump_length, le64_to_cpu(dev_table[i].length));
if (dump_length == SIZE_MAX) {
if (check_add_overflow(dump_length,
le64_to_cpu(dev_table[i].length),
&dump_length)) {
/* Discard the dump */
sahara_send_reset(context);
return;
@@ -568,14 +607,17 @@ static void sahara_parse_dump_table(struct sahara_context *context)
dev_table[i].filename);
}
dump_length = size_add(dump_length, sizeof(*dump_meta));
if (dump_length == SIZE_MAX) {
if (check_add_overflow(dump_length, (u64)sizeof(*dump_meta), &dump_length)) {
/* Discard the dump */
sahara_send_reset(context);
return;
}
dump_length = size_add(dump_length, size_mul(sizeof(*image_out_table), table_nents));
if (dump_length == SIZE_MAX) {
if (check_mul_overflow((u64)sizeof(*image_out_table), table_nents, &mul_bytes)) {
/* Discard the dump */
sahara_send_reset(context);
return;
}
if (check_add_overflow(dump_length, mul_bytes, &dump_length)) {
/* Discard the dump */
sahara_send_reset(context);
return;
@@ -615,7 +657,7 @@ static void sahara_parse_dump_table(struct sahara_context *context)
/* Request the first chunk of the first image */
context->dump_image = &image_out_table[0];
dump_length = min(context->dump_image->length, SAHARA_READ_MAX_SIZE);
dump_length = min_t(u64, context->dump_image->length, SAHARA_READ_MAX_SIZE);
/* Avoid requesting EOI sized data so that we can identify errors */
if (dump_length == SAHARA_END_OF_IMAGE_LENGTH)
dump_length = SAHARA_END_OF_IMAGE_LENGTH / 2;
@@ -663,7 +705,7 @@ static void sahara_parse_dump_image(struct sahara_context *context)
/* Get next image chunk */
dump_length = context->dump_image->length - context->dump_image_offset;
dump_length = min(dump_length, SAHARA_READ_MAX_SIZE);
dump_length = min_t(u64, dump_length, SAHARA_READ_MAX_SIZE);
/* Avoid requesting EOI sized data so that we can identify errors */
if (dump_length == SAHARA_END_OF_IMAGE_LENGTH)
dump_length = SAHARA_END_OF_IMAGE_LENGTH / 2;
@@ -742,6 +784,13 @@ error:
sahara_send_reset(context);
}
static void sahara_read_data_processing(struct work_struct *work)
{
struct sahara_context *context = container_of(work, struct sahara_context, read_data_work);
read_data_helper(context, 0);
}
static int sahara_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_id *id)
{
struct sahara_context *context;
@@ -756,35 +805,57 @@ static int sahara_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_
if (!context->rx)
return -ENOMEM;
/*
* AIC100 defines SAHARA_TRANSFER_MAX_SIZE as the largest value it
* will request for READ_DATA. This is larger than
* SAHARA_PACKET_MAX_SIZE, and we need 9x SAHARA_PACKET_MAX_SIZE to
* cover SAHARA_TRANSFER_MAX_SIZE. When the remote side issues a
* READ_DATA, it requires a transfer of the exact size requested. We
* can use MHI_CHAIN to link multiple buffers into a single transfer
* but the remote side will not consume the buffers until it sees an
* EOT, thus we need to allocate enough buffers to put in the tx fifo
* to cover an entire READ_DATA request of the max size.
*/
for (i = 0; i < SAHARA_NUM_TX_BUF; ++i) {
context->tx[i] = devm_kzalloc(&mhi_dev->dev, SAHARA_PACKET_MAX_SIZE, GFP_KERNEL);
if (!context->tx[i])
return -ENOMEM;
}
context->mhi_dev = mhi_dev;
INIT_WORK(&context->fw_work, sahara_processing);
INIT_WORK(&context->dump_work, sahara_dump_processing);
if (!strcmp(mhi_dev->mhi_cntrl->name, "AIC200")) {
context->image_table = aic200_image_table;
context->table_size = ARRAY_SIZE(aic200_image_table);
} else {
context->image_table = aic100_image_table;
context->table_size = ARRAY_SIZE(aic100_image_table);
context->non_streaming = true;
}
/*
* There are two firmware implementations for READ_DATA handling.
* The older "SBL" implementation defines a Sahara transfer size, and
* expects that the response is a single transport transfer. If the
* FW wants to transfer a file that is larger than the transfer size,
* the FW will issue multiple READ_DATA commands. For this
* implementation, we need to allocate enough buffers to contain the
* entire Sahara transfer size.
*
* The newer "XBL" implementation does not define a maximum transfer
* size and instead expects the data to be streamed over using the
* transport level MTU. The FW will issue a single READ_DATA command
* of whatever size, and consume multiple transport level transfers
* until the expected amount of data is consumed. For this
* implementation we only need a single buffer of the transport MTU
* but we'll need to be able to use it multiple times for a single
* READ_DATA request.
*
* AIC100 is the SBL implementation and defines SAHARA_TRANSFER_MAX_SIZE
* and we need 9x SAHARA_PACKET_MAX_SIZE to cover that. We can use
* MHI_CHAIN to link multiple buffers into a single transfer but the
* remote side will not consume the buffers until it sees an EOT, thus
* we need to allocate enough buffers to put in the tx fifo to cover an
* entire READ_DATA request of the max size.
*
* AIC200 is the XBL implementation, and so a single buffer will work.
*/
for (i = 0; i < SAHARA_NUM_TX_BUF; ++i) {
context->tx[i] = devm_kzalloc(&mhi_dev->dev,
SAHARA_PACKET_MAX_SIZE,
GFP_KERNEL);
if (!context->tx[i])
return -ENOMEM;
if (is_streaming(context))
break;
}
context->mhi_dev = mhi_dev;
INIT_WORK(&context->fw_work, sahara_processing);
INIT_WORK(&context->dump_work, sahara_dump_processing);
INIT_WORK(&context->read_data_work, sahara_read_data_processing);
context->active_image_id = SAHARA_IMAGE_ID_NONE;
dev_set_drvdata(&mhi_dev->dev, context);
@@ -814,6 +885,10 @@ static void sahara_mhi_remove(struct mhi_device *mhi_dev)
static void sahara_mhi_ul_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result)
{
struct sahara_context *context = dev_get_drvdata(&mhi_dev->dev);
if (!mhi_result->transaction_status && context->read_data_length && is_streaming(context))
schedule_work(&context->read_data_work);
}
static void sahara_mhi_dl_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result)

View File

@@ -12,13 +12,3 @@ config DMABUF_HEAPS_CMA
Choose this option to enable dma-buf CMA heap. This heap is backed
by the Contiguous Memory Allocator (CMA). If your system has these
regions, you should say Y here.
config DMABUF_HEAPS_CMA_LEGACY
bool "Legacy DMA-BUF CMA Heap"
default y
depends on DMABUF_HEAPS_CMA
help
Add a duplicate CMA-backed dma-buf heap with legacy naming derived
from the CMA area's devicetree node, or "reserved" if the area is not
defined in the devicetree. This uses the same underlying allocator as
CONFIG_DMABUF_HEAPS_CMA.

View File

@@ -14,6 +14,7 @@
#include <linux/cma.h>
#include <linux/dma-buf.h>
#include <linux/dma-buf/heaps/cma.h>
#include <linux/dma-heap.h>
#include <linux/dma-map-ops.h>
#include <linux/err.h>
@@ -21,12 +22,27 @@
#include <linux/io.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_reserved_mem.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#define DEFAULT_CMA_NAME "default_cma_region"
static struct cma *dma_areas[MAX_CMA_AREAS] __initdata;
static unsigned int dma_areas_num __initdata;
int __init dma_heap_cma_register_heap(struct cma *cma)
{
if (dma_areas_num >= ARRAY_SIZE(dma_areas))
return -EINVAL;
dma_areas[dma_areas_num++] = cma;
return 0;
}
struct cma_heap {
struct dma_heap *heap;
struct cma *cma;
@@ -395,33 +411,30 @@ static int __init __add_cma_heap(struct cma *cma, const char *name)
return 0;
}
static int __init add_default_cma_heap(void)
static int __init add_cma_heaps(void)
{
struct cma *default_cma = dev_get_cma_area(NULL);
const char *legacy_cma_name;
unsigned int i;
int ret;
if (!default_cma)
return 0;
if (default_cma) {
ret = __add_cma_heap(default_cma, DEFAULT_CMA_NAME);
if (ret)
return ret;
}
ret = __add_cma_heap(default_cma, DEFAULT_CMA_NAME);
if (ret)
return ret;
for (i = 0; i < dma_areas_num; i++) {
struct cma *cma = dma_areas[i];
if (IS_ENABLED(CONFIG_DMABUF_HEAPS_CMA_LEGACY)) {
legacy_cma_name = cma_get_name(default_cma);
if (!strcmp(legacy_cma_name, DEFAULT_CMA_NAME)) {
pr_warn("legacy name and default name are the same, skipping legacy heap\n");
return 0;
ret = __add_cma_heap(cma, cma_get_name(cma));
if (ret) {
pr_warn("Failed to add CMA heap %s", cma_get_name(cma));
continue;
}
ret = __add_cma_heap(default_cma, legacy_cma_name);
if (ret)
pr_warn("failed to add legacy heap: %pe\n",
ERR_PTR(ret));
}
return 0;
}
module_init(add_default_cma_heap);
module_init(add_cma_heaps);
MODULE_DESCRIPTION("DMA-BUF CMA Heap");

View File

@@ -5219,7 +5219,7 @@ int amdgpu_device_suspend(struct drm_device *dev, bool notify_clients)
dev_warn(adev->dev, "smart shift update failed\n");
if (notify_clients)
drm_client_dev_suspend(adev_to_drm(adev), false);
drm_client_dev_suspend(adev_to_drm(adev));
cancel_delayed_work_sync(&adev->delayed_init_work);
@@ -5353,7 +5353,7 @@ exit:
flush_delayed_work(&adev->delayed_init_work);
if (notify_clients)
drm_client_dev_resume(adev_to_drm(adev), false);
drm_client_dev_resume(adev_to_drm(adev));
amdgpu_ras_resume(adev);
@@ -5958,7 +5958,7 @@ int amdgpu_device_reinit_after_reset(struct amdgpu_reset_context *reset_context)
if (r)
goto out;
drm_client_dev_resume(adev_to_drm(tmp_adev), false);
drm_client_dev_resume(adev_to_drm(tmp_adev));
/*
* The GPU enters bad state once faulty pages
@@ -6293,7 +6293,7 @@ static void amdgpu_device_halt_activities(struct amdgpu_device *adev,
*/
amdgpu_unregister_gpu_instance(tmp_adev);
drm_client_dev_suspend(adev_to_drm(tmp_adev), false);
drm_client_dev_suspend(adev_to_drm(tmp_adev));
/* disable ras on ALL IPs */
if (!need_emergency_restart && !amdgpu_reset_in_dpc(adev) &&

View File

@@ -12446,7 +12446,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
int j = state->num_private_objs-1;
dm_atomic_destroy_state(obj,
state->private_objs[i].state);
state->private_objs[i].state_to_destroy);
/* If i is not at the end of the array then the
* last element needs to be moved to where i was
@@ -12457,7 +12457,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
state->private_objs[j];
state->private_objs[j].ptr = NULL;
state->private_objs[j].state = NULL;
state->private_objs[j].state_to_destroy = NULL;
state->private_objs[j].old_state = NULL;
state->private_objs[j].new_state = NULL;

View File

@@ -111,6 +111,7 @@ komeda_crtc_atomic_check(struct drm_crtc *crtc,
static int
komeda_crtc_prepare(struct komeda_crtc *kcrtc)
{
struct drm_device *drm = kcrtc->base.dev;
struct komeda_dev *mdev = kcrtc->base.dev->dev_private;
struct komeda_pipeline *master = kcrtc->master;
struct komeda_crtc_state *kcrtc_st = to_kcrtc_st(kcrtc->base.state);
@@ -128,8 +129,8 @@ komeda_crtc_prepare(struct komeda_crtc *kcrtc)
err = mdev->funcs->change_opmode(mdev, new_mode);
if (err) {
DRM_ERROR("failed to change opmode: 0x%x -> 0x%x.\n,",
mdev->dpmode, new_mode);
drm_err(drm, "failed to change opmode: 0x%x -> 0x%x.\n,",
mdev->dpmode, new_mode);
goto unlock;
}
@@ -142,18 +143,18 @@ komeda_crtc_prepare(struct komeda_crtc *kcrtc)
if (new_mode != KOMEDA_MODE_DUAL_DISP) {
err = clk_set_rate(mdev->aclk, komeda_crtc_get_aclk(kcrtc_st));
if (err)
DRM_ERROR("failed to set aclk.\n");
drm_err(drm, "failed to set aclk.\n");
err = clk_prepare_enable(mdev->aclk);
if (err)
DRM_ERROR("failed to enable aclk.\n");
drm_err(drm, "failed to enable aclk.\n");
}
err = clk_set_rate(master->pxlclk, mode->crtc_clock * 1000);
if (err)
DRM_ERROR("failed to set pxlclk for pipe%d\n", master->id);
drm_err(drm, "failed to set pxlclk for pipe%d\n", master->id);
err = clk_prepare_enable(master->pxlclk);
if (err)
DRM_ERROR("failed to enable pxl clk for pipe%d.\n", master->id);
drm_err(drm, "failed to enable pxl clk for pipe%d.\n", master->id);
unlock:
mutex_unlock(&mdev->lock);
@@ -164,6 +165,7 @@ unlock:
static int
komeda_crtc_unprepare(struct komeda_crtc *kcrtc)
{
struct drm_device *drm = kcrtc->base.dev;
struct komeda_dev *mdev = kcrtc->base.dev->dev_private;
struct komeda_pipeline *master = kcrtc->master;
u32 new_mode;
@@ -180,8 +182,8 @@ komeda_crtc_unprepare(struct komeda_crtc *kcrtc)
err = mdev->funcs->change_opmode(mdev, new_mode);
if (err) {
DRM_ERROR("failed to change opmode: 0x%x -> 0x%x.\n,",
mdev->dpmode, new_mode);
drm_err(drm, "failed to change opmode: 0x%x -> 0x%x.\n,",
mdev->dpmode, new_mode);
goto unlock;
}
@@ -200,6 +202,7 @@ unlock:
void komeda_crtc_handle_event(struct komeda_crtc *kcrtc,
struct komeda_events *evts)
{
struct drm_device *drm = kcrtc->base.dev;
struct drm_crtc *crtc = &kcrtc->base;
u32 events = evts->pipes[kcrtc->master->id];
@@ -212,7 +215,7 @@ void komeda_crtc_handle_event(struct komeda_crtc *kcrtc,
if (wb_conn)
drm_writeback_signal_completion(&wb_conn->base, 0);
else
DRM_WARN("CRTC[%d]: EOW happen but no wb_connector.\n",
drm_warn(drm, "CRTC[%d]: EOW happen but no wb_connector.\n",
drm_crtc_index(&kcrtc->base));
}
/* will handle it together with the write back support */
@@ -236,7 +239,7 @@ void komeda_crtc_handle_event(struct komeda_crtc *kcrtc,
crtc->state->event = NULL;
drm_crtc_send_vblank_event(crtc, event);
} else {
DRM_WARN("CRTC[%d]: FLIP happened but no pending commit.\n",
drm_warn(drm, "CRTC[%d]: FLIP happened but no pending commit.\n",
drm_crtc_index(&kcrtc->base));
}
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
@@ -309,7 +312,7 @@ komeda_crtc_flush_and_wait_for_flip_done(struct komeda_crtc *kcrtc,
/* wait the flip take affect.*/
if (wait_for_completion_timeout(flip_done, HZ) == 0) {
DRM_ERROR("wait pipe%d flip done timeout\n", kcrtc->master->id);
drm_err(drm, "wait pipe%d flip done timeout\n", kcrtc->master->id);
if (!input_flip_done) {
unsigned long flags;
@@ -562,6 +565,7 @@ static const struct drm_crtc_funcs komeda_crtc_funcs = {
int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms,
struct komeda_dev *mdev)
{
struct drm_device *drm = &kms->base;
struct komeda_crtc *crtc;
struct komeda_pipeline *master;
char str[16];
@@ -581,7 +585,7 @@ int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms,
else
sprintf(str, "None");
DRM_INFO("CRTC-%d: master(pipe-%d) slave(%s).\n",
drm_info(drm, "CRTC-%d: master(pipe-%d) slave(%s).\n",
kms->n_crtcs, master->id, str);
kms->n_crtcs++;
@@ -613,6 +617,7 @@ static int komeda_attach_bridge(struct device *dev,
struct komeda_pipeline *pipe,
struct drm_encoder *encoder)
{
struct drm_device *drm = encoder->dev;
struct drm_bridge *bridge;
int err;
@@ -624,7 +629,7 @@ static int komeda_attach_bridge(struct device *dev,
err = drm_bridge_attach(encoder, bridge, NULL, 0);
if (err)
dev_err(dev, "bridge_attach() failed for pipe: %s\n",
drm_err(drm, "bridge_attach() failed for pipe: %s\n",
of_node_full_name(pipe->of_node));
return err;

View File

@@ -263,7 +263,7 @@ static int malidp_se_check_scaling(struct malidp_plane *mp,
struct drm_plane_state *state)
{
struct drm_crtc_state *crtc_state =
drm_atomic_get_existing_crtc_state(state->state, state->crtc);
drm_atomic_get_new_crtc_state(state->state, state->crtc);
struct malidp_crtc_state *mc;
u32 src_w, src_h;
int ret;

View File

@@ -94,12 +94,7 @@ int armada_drm_plane_atomic_check(struct drm_plane *plane,
return 0;
}
if (state)
crtc_state = drm_atomic_get_existing_crtc_state(state,
crtc);
else
crtc_state = crtc->state;
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
0,
INT_MAX, true, false);

View File

@@ -211,6 +211,11 @@ void ast_2000_detect_tx_chip(struct ast_device *ast, bool need_post)
__ast_device_set_tx_chip(ast, tx_chip);
}
static const struct ast_device_quirks ast_2000_device_quirks = {
.crtc_mem_req_threshold_low = 31,
.crtc_mem_req_threshold_high = 47,
};
struct drm_device *ast_2000_device_create(struct pci_dev *pdev,
const struct drm_driver *drv,
enum ast_chip chip,
@@ -228,7 +233,9 @@ struct drm_device *ast_2000_device_create(struct pci_dev *pdev,
return ERR_CAST(ast);
dev = &ast->base;
ast_device_init(ast, chip, config_mode, regs, ioregs);
ast_device_init(ast, chip, config_mode, regs, ioregs, &ast_2000_device_quirks);
ast->dclk_table = ast_2000_dclk_table;
ast_2000_detect_tx_chip(ast, need_post);

View File

@@ -432,6 +432,11 @@ static void ast_2100_detect_widescreen(struct ast_device *ast)
ast->support_wuxga = true;
}
static const struct ast_device_quirks ast_2100_device_quirks = {
.crtc_mem_req_threshold_low = 47,
.crtc_mem_req_threshold_high = 63,
};
struct drm_device *ast_2100_device_create(struct pci_dev *pdev,
const struct drm_driver *drv,
enum ast_chip chip,
@@ -449,7 +454,9 @@ struct drm_device *ast_2100_device_create(struct pci_dev *pdev,
return ERR_CAST(ast);
dev = &ast->base;
ast_device_init(ast, chip, config_mode, regs, ioregs);
ast_device_init(ast, chip, config_mode, regs, ioregs, &ast_2100_device_quirks);
ast->dclk_table = ast_2000_dclk_table;
ast_2000_detect_tx_chip(ast, need_post);

View File

@@ -43,6 +43,11 @@ static void ast_2200_detect_widescreen(struct ast_device *ast)
ast->support_wuxga = true;
}
static const struct ast_device_quirks ast_2200_device_quirks = {
.crtc_mem_req_threshold_low = 47,
.crtc_mem_req_threshold_high = 63,
};
struct drm_device *ast_2200_device_create(struct pci_dev *pdev,
const struct drm_driver *drv,
enum ast_chip chip,
@@ -60,7 +65,9 @@ struct drm_device *ast_2200_device_create(struct pci_dev *pdev,
return ERR_CAST(ast);
dev = &ast->base;
ast_device_init(ast, chip, config_mode, regs, ioregs);
ast_device_init(ast, chip, config_mode, regs, ioregs, &ast_2200_device_quirks);
ast->dclk_table = ast_2000_dclk_table;
ast_2000_detect_tx_chip(ast, need_post);

View File

@@ -1407,6 +1407,11 @@ static void ast_2300_detect_widescreen(struct ast_device *ast)
ast->support_wuxga = true;
}
static const struct ast_device_quirks ast_2300_device_quirks = {
.crtc_mem_req_threshold_low = 96,
.crtc_mem_req_threshold_high = 120,
};
struct drm_device *ast_2300_device_create(struct pci_dev *pdev,
const struct drm_driver *drv,
enum ast_chip chip,
@@ -1424,7 +1429,9 @@ struct drm_device *ast_2300_device_create(struct pci_dev *pdev,
return ERR_CAST(ast);
dev = &ast->base;
ast_device_init(ast, chip, config_mode, regs, ioregs);
ast_device_init(ast, chip, config_mode, regs, ioregs, &ast_2300_device_quirks);
ast->dclk_table = ast_2000_dclk_table;
ast_2300_detect_tx_chip(ast);

View File

@@ -44,6 +44,11 @@ static void ast_2400_detect_widescreen(struct ast_device *ast)
ast->support_wuxga = true;
}
static const struct ast_device_quirks ast_2400_device_quirks = {
.crtc_mem_req_threshold_low = 96,
.crtc_mem_req_threshold_high = 120,
};
struct drm_device *ast_2400_device_create(struct pci_dev *pdev,
const struct drm_driver *drv,
enum ast_chip chip,
@@ -61,7 +66,9 @@ struct drm_device *ast_2400_device_create(struct pci_dev *pdev,
return ERR_CAST(ast);
dev = &ast->base;
ast_device_init(ast, chip, config_mode, regs, ioregs);
ast_device_init(ast, chip, config_mode, regs, ioregs, &ast_2400_device_quirks);
ast->dclk_table = ast_2000_dclk_table;
ast_2300_detect_tx_chip(ast);

View File

@@ -618,6 +618,12 @@ static void ast_2500_detect_widescreen(struct ast_device *ast)
ast->support_wuxga = true;
}
static const struct ast_device_quirks ast_2500_device_quirks = {
.crtc_mem_req_threshold_low = 96,
.crtc_mem_req_threshold_high = 120,
.crtc_hsync_precatch_needed = true,
};
struct drm_device *ast_2500_device_create(struct pci_dev *pdev,
const struct drm_driver *drv,
enum ast_chip chip,
@@ -635,7 +641,9 @@ struct drm_device *ast_2500_device_create(struct pci_dev *pdev,
return ERR_CAST(ast);
dev = &ast->base;
ast_device_init(ast, chip, config_mode, regs, ioregs);
ast_device_init(ast, chip, config_mode, regs, ioregs, &ast_2500_device_quirks);
ast->dclk_table = ast_2500_dclk_table;
ast_2300_detect_tx_chip(ast);

View File

@@ -59,6 +59,13 @@ static void ast_2600_detect_widescreen(struct ast_device *ast)
ast->support_wuxga = true;
}
static const struct ast_device_quirks ast_2600_device_quirks = {
.crtc_mem_req_threshold_low = 160,
.crtc_mem_req_threshold_high = 224,
.crtc_hsync_precatch_needed = true,
.crtc_hsync_add4_needed = true,
};
struct drm_device *ast_2600_device_create(struct pci_dev *pdev,
const struct drm_driver *drv,
enum ast_chip chip,
@@ -76,7 +83,9 @@ struct drm_device *ast_2600_device_create(struct pci_dev *pdev,
return ERR_CAST(ast);
dev = &ast->base;
ast_device_init(ast, chip, config_mode, regs, ioregs);
ast_device_init(ast, chip, config_mode, regs, ioregs, &ast_2600_device_quirks);
ast->dclk_table = ast_2500_dclk_table;
ast_2300_detect_tx_chip(ast);

View File

@@ -51,8 +51,10 @@ void ast_device_init(struct ast_device *ast,
enum ast_chip chip,
enum ast_config_mode config_mode,
void __iomem *regs,
void __iomem *ioregs)
void __iomem *ioregs,
const struct ast_device_quirks *quirks)
{
ast->quirks = quirks;
ast->chip = chip;
ast->config_mode = config_mode;
ast->regs = regs;

View File

@@ -164,9 +164,31 @@ to_ast_connector(struct drm_connector *connector)
* Device
*/
struct ast_device_quirks {
/*
* CRTC memory request threshold
*/
unsigned char crtc_mem_req_threshold_low;
unsigned char crtc_mem_req_threshold_high;
/*
* Adjust hsync values to load next scanline early. Signalled
* by AST2500PreCatchCRT in VBIOS mode flags.
*/
bool crtc_hsync_precatch_needed;
/*
* Workaround for modes with HSync Time that is not a multiple
* of 8 (e.g., 1920x1080@60Hz, HSync +44 pixels).
*/
bool crtc_hsync_add4_needed;
};
struct ast_device {
struct drm_device base;
const struct ast_device_quirks *quirks;
void __iomem *regs;
void __iomem *ioregs;
void __iomem *dp501_fw_buf;
@@ -174,6 +196,8 @@ struct ast_device {
enum ast_config_mode config_mode;
enum ast_chip chip;
const struct ast_vbios_dclk_info *dclk_table;
void __iomem *vram;
unsigned long vram_base;
unsigned long vram_size;
@@ -412,7 +436,8 @@ void ast_device_init(struct ast_device *ast,
enum ast_chip chip,
enum ast_config_mode config_mode,
void __iomem *regs,
void __iomem *ioregs);
void __iomem *ioregs,
const struct ast_device_quirks *quirks);
void __ast_device_set_tx_chip(struct ast_device *ast, enum ast_tx_chip tx_chip);
/* ast_2000.c */

View File

@@ -241,16 +241,15 @@ static void ast_set_std_reg(struct ast_device *ast,
ast_set_index_reg(ast, AST_IO_VGAGRI, i, stdtable->gr[i]);
}
static void ast_set_crtc_reg(struct ast_device *ast,
struct drm_display_mode *mode,
static void ast_set_crtc_reg(struct ast_device *ast, struct drm_display_mode *mode,
const struct ast_vbios_enhtable *vmode)
{
u8 jreg05 = 0, jreg07 = 0, jreg09 = 0, jregAC = 0, jregAD = 0, jregAE = 0;
u16 temp, precache = 0;
u16 temp;
unsigned char crtc_hsync_precatch = 0;
if ((IS_AST_GEN6(ast) || IS_AST_GEN7(ast)) &&
(vmode->flags & AST2500PreCatchCRT))
precache = 40;
if (ast->quirks->crtc_hsync_precatch_needed && (vmode->flags & AST2500PreCatchCRT))
crtc_hsync_precatch = 40;
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x11, 0x7f, 0x00);
@@ -276,12 +275,12 @@ static void ast_set_crtc_reg(struct ast_device *ast,
jregAD |= 0x01; /* HBE D[5] */
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x03, 0xE0, (temp & 0x1f));
temp = ((mode->crtc_hsync_start-precache) >> 3) - 1;
temp = ((mode->crtc_hsync_start - crtc_hsync_precatch) >> 3) - 1;
if (temp & 0x100)
jregAC |= 0x40; /* HRS D[5] */
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x04, 0x00, temp);
temp = (((mode->crtc_hsync_end-precache) >> 3) - 1) & 0x3f;
temp = (((mode->crtc_hsync_end - crtc_hsync_precatch) >> 3) - 1) & 0x3f;
if (temp & 0x20)
jregAD |= 0x04; /* HRE D[5] */
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x05, 0x60, (u8)((temp & 0x1f) | jreg05));
@@ -289,8 +288,7 @@ static void ast_set_crtc_reg(struct ast_device *ast,
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xAC, 0x00, jregAC);
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xAD, 0x00, jregAD);
// Workaround for HSync Time non octave pixels (1920x1080@60Hz HSync 44 pixels);
if (IS_AST_GEN7(ast) && (mode->crtc_vdisplay == 1080))
if (ast->quirks->crtc_hsync_add4_needed && mode->crtc_vdisplay == 1080)
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xFC, 0xFD, 0x02);
else
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xFC, 0xFD, 0x00);
@@ -348,7 +346,7 @@ static void ast_set_crtc_reg(struct ast_device *ast,
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x09, 0xdf, jreg09);
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xAE, 0x00, (jregAE | 0x80));
if (precache)
if (crtc_hsync_precatch)
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xb6, 0x3f, 0x80);
else
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xb6, 0x3f, 0x00);
@@ -370,12 +368,7 @@ static void ast_set_dclk_reg(struct ast_device *ast,
struct drm_display_mode *mode,
const struct ast_vbios_enhtable *vmode)
{
const struct ast_vbios_dclk_info *clk_info;
if (IS_AST_GEN6(ast) || IS_AST_GEN7(ast))
clk_info = &ast_2500_dclk_table[vmode->dclk_index];
else
clk_info = &ast_2000_dclk_table[vmode->dclk_index];
const struct ast_vbios_dclk_info *clk_info = &ast->dclk_table[vmode->dclk_index];
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xc0, 0x00, clk_info->param1);
ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xc1, 0x00, clk_info->param2);
@@ -415,20 +408,11 @@ static void ast_set_color_reg(struct ast_device *ast,
static void ast_set_crtthd_reg(struct ast_device *ast)
{
/* Set Threshold */
if (IS_AST_GEN7(ast)) {
ast_set_index_reg(ast, AST_IO_VGACRI, 0xa7, 0xe0);
ast_set_index_reg(ast, AST_IO_VGACRI, 0xa6, 0xa0);
} else if (IS_AST_GEN6(ast) || IS_AST_GEN5(ast) || IS_AST_GEN4(ast)) {
ast_set_index_reg(ast, AST_IO_VGACRI, 0xa7, 0x78);
ast_set_index_reg(ast, AST_IO_VGACRI, 0xa6, 0x60);
} else if (IS_AST_GEN3(ast) || IS_AST_GEN2(ast)) {
ast_set_index_reg(ast, AST_IO_VGACRI, 0xa7, 0x3f);
ast_set_index_reg(ast, AST_IO_VGACRI, 0xa6, 0x2f);
} else {
ast_set_index_reg(ast, AST_IO_VGACRI, 0xa7, 0x2f);
ast_set_index_reg(ast, AST_IO_VGACRI, 0xa6, 0x1f);
}
u8 vgacra6 = ast->quirks->crtc_mem_req_threshold_low;
u8 vgacra7 = ast->quirks->crtc_mem_req_threshold_high;
ast_set_index_reg(ast, AST_IO_VGACRI, 0xa7, vgacra7);
ast_set_index_reg(ast, AST_IO_VGACRI, 0xa6, vgacra6);
}
static void ast_set_sync_reg(struct ast_device *ast,

View File

@@ -20,6 +20,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
@@ -215,32 +216,32 @@ static void atmel_hlcdc_crtc_atomic_disable(struct drm_crtc *c,
if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
!(status & ATMEL_XLCDC_CM),
10, 1000))
dev_warn(dev->dev, "Atmel LCDC status register CMSTS timeout\n");
drm_warn(dev, "Atmel LCDC status register CMSTS timeout\n");
regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_XLCDC_SD);
if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
status & ATMEL_XLCDC_SD,
10, 1000))
dev_warn(dev->dev, "Atmel LCDC status register SDSTS timeout\n");
drm_warn(dev, "Atmel LCDC status register SDSTS timeout\n");
}
regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_DISP);
if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
!(status & ATMEL_HLCDC_DISP),
10, 1000))
dev_warn(dev->dev, "Atmel LCDC status register DISPSTS timeout\n");
drm_warn(dev, "Atmel LCDC status register DISPSTS timeout\n");
regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_SYNC);
if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
!(status & ATMEL_HLCDC_SYNC),
10, 1000))
dev_warn(dev->dev, "Atmel LCDC status register LCDSTS timeout\n");
drm_warn(dev, "Atmel LCDC status register LCDSTS timeout\n");
regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_PIXEL_CLK);
if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
!(status & ATMEL_HLCDC_PIXEL_CLK),
10, 1000))
dev_warn(dev->dev, "Atmel LCDC status register CLKSTS timeout\n");
drm_warn(dev, "Atmel LCDC status register CLKSTS timeout\n");
clk_disable_unprepare(crtc->dc->hlcdc->sys_clk);
pinctrl_pm_select_sleep_state(dev->dev);
@@ -269,32 +270,32 @@ static void atmel_hlcdc_crtc_atomic_enable(struct drm_crtc *c,
if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
status & ATMEL_HLCDC_PIXEL_CLK,
10, 1000))
dev_warn(dev->dev, "Atmel LCDC status register CLKSTS timeout\n");
drm_warn(dev, "Atmel LCDC status register CLKSTS timeout\n");
regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_SYNC);
if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
status & ATMEL_HLCDC_SYNC,
10, 1000))
dev_warn(dev->dev, "Atmel LCDC status register LCDSTS timeout\n");
drm_warn(dev, "Atmel LCDC status register LCDSTS timeout\n");
regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_DISP);
if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
status & ATMEL_HLCDC_DISP,
10, 1000))
dev_warn(dev->dev, "Atmel LCDC status register DISPSTS timeout\n");
drm_warn(dev, "Atmel LCDC status register DISPSTS timeout\n");
if (crtc->dc->desc->is_xlcdc) {
regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_XLCDC_CM);
if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
status & ATMEL_XLCDC_CM,
10, 1000))
dev_warn(dev->dev, "Atmel LCDC status register CMSTS timeout\n");
drm_warn(dev, "Atmel LCDC status register CMSTS timeout\n");
regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_XLCDC_SD);
if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
!(status & ATMEL_XLCDC_SD),
10, 1000))
dev_warn(dev->dev, "Atmel LCDC status register SDSTS timeout\n");
drm_warn(dev, "Atmel LCDC status register SDSTS timeout\n");
}
pm_runtime_put_sync(dev->dev);

View File

@@ -724,19 +724,19 @@ static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev)
ret = atmel_hlcdc_create_outputs(dev);
if (ret) {
dev_err(dev->dev, "failed to create HLCDC outputs: %d\n", ret);
drm_err(dev, "failed to create HLCDC outputs: %d\n", ret);
return ret;
}
ret = atmel_hlcdc_create_planes(dev);
if (ret) {
dev_err(dev->dev, "failed to create planes: %d\n", ret);
drm_err(dev, "failed to create planes: %d\n", ret);
return ret;
}
ret = atmel_hlcdc_crtc_create(dev);
if (ret) {
dev_err(dev->dev, "failed to create crtc\n");
drm_err(dev, "failed to create crtc\n");
return ret;
}
@@ -778,7 +778,7 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev)
ret = clk_prepare_enable(dc->hlcdc->periph_clk);
if (ret) {
dev_err(dev->dev, "failed to enable periph_clk\n");
drm_err(dev, "failed to enable periph_clk\n");
return ret;
}
@@ -786,13 +786,13 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev)
ret = drm_vblank_init(dev, 1);
if (ret < 0) {
dev_err(dev->dev, "failed to initialize vblank\n");
drm_err(dev, "failed to initialize vblank\n");
goto err_periph_clk_disable;
}
ret = atmel_hlcdc_dc_modeset_init(dev);
if (ret < 0) {
dev_err(dev->dev, "failed to initialize mode setting\n");
drm_err(dev, "failed to initialize mode setting\n");
goto err_periph_clk_disable;
}
@@ -802,7 +802,7 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev)
ret = atmel_hlcdc_dc_irq_install(dev, dc->hlcdc->irq);
pm_runtime_put_sync(dev->dev);
if (ret < 0) {
dev_err(dev->dev, "failed to install IRQ handler\n");
drm_err(dev, "failed to install IRQ handler\n");
goto err_periph_clk_disable;
}

View File

@@ -378,7 +378,8 @@ struct atmel_lcdc_dc_ops {
void (*lcdc_update_buffers)(struct atmel_hlcdc_plane *plane,
struct atmel_hlcdc_plane_state *state,
u32 sr, int i);
void (*lcdc_atomic_disable)(struct atmel_hlcdc_plane *plane);
void (*lcdc_atomic_disable)(struct atmel_hlcdc_plane *plane,
struct atmel_hlcdc_dc *dc);
void (*lcdc_update_general_settings)(struct atmel_hlcdc_plane *plane,
struct atmel_hlcdc_plane_state *state);
void (*lcdc_atomic_update)(struct atmel_hlcdc_plane *plane,

View File

@@ -15,6 +15,7 @@
#include <drm/drm_bridge.h>
#include <drm/drm_encoder.h>
#include <drm/drm_of.h>
#include <drm/drm_print.h>
#include <drm/drm_simple_kms_helper.h>
#include "atmel_hlcdc_dc.h"
@@ -92,7 +93,7 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev, int endpoint)
output->bus_fmt = atmel_hlcdc_of_bus_fmt(ep);
of_node_put(ep);
if (output->bus_fmt < 0) {
dev_err(dev->dev, "endpoint %d: invalid bus width\n", endpoint);
drm_err(dev, "endpoint %d: invalid bus width\n", endpoint);
return -EINVAL;
}

View File

@@ -365,13 +365,34 @@ void atmel_xlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
xfactor);
/*
* With YCbCr 4:2:2 and YCbYcr 4:2:0 window resampling, configuration
* register LCDC_HEOCFG25.VXSCFACT and LCDC_HEOCFG27.HXSCFACT is half
* With YCbCr 4:2:0 window resampling, configuration register
* LCDC_HEOCFG25.VXSCFACT and LCDC_HEOCFG27.HXSCFACT values are half
* the value of yfactor and xfactor.
*
* On the other hand, with YCbCr 4:2:2 window resampling, only the
* configuration register LCDC_HEOCFG27.HXSCFACT value is half the value
* of the xfactor; the value of LCDC_HEOCFG25.VXSCFACT is yfactor (no
* division by 2).
*/
if (state->base.fb->format->format == DRM_FORMAT_YUV420) {
switch (state->base.fb->format->format) {
/* YCbCr 4:2:2 */
case DRM_FORMAT_YUYV:
case DRM_FORMAT_UYVY:
case DRM_FORMAT_YVYU:
case DRM_FORMAT_VYUY:
case DRM_FORMAT_YUV422:
case DRM_FORMAT_NV61:
xfactor /= 2;
break;
/* YCbCr 4:2:0 */
case DRM_FORMAT_YUV420:
case DRM_FORMAT_NV21:
yfactor /= 2;
xfactor /= 2;
break;
default:
break;
}
atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config + 2,
@@ -714,7 +735,7 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
if (!hstate->base.crtc || WARN_ON(!fb))
return 0;
crtc_state = drm_atomic_get_existing_crtc_state(state, s->crtc);
crtc_state = drm_atomic_get_new_crtc_state(state, s->crtc);
mode = &crtc_state->adjusted_mode;
ret = drm_atomic_helper_check_plane_state(s, crtc_state,
@@ -816,7 +837,8 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
return 0;
}
static void atmel_hlcdc_atomic_disable(struct atmel_hlcdc_plane *plane)
static void atmel_hlcdc_atomic_disable(struct atmel_hlcdc_plane *plane,
struct atmel_hlcdc_dc *dc)
{
/* Disable interrupts */
atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
@@ -832,7 +854,8 @@ static void atmel_hlcdc_atomic_disable(struct atmel_hlcdc_plane *plane)
atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
}
static void atmel_xlcdc_atomic_disable(struct atmel_hlcdc_plane *plane)
static void atmel_xlcdc_atomic_disable(struct atmel_hlcdc_plane *plane,
struct atmel_hlcdc_dc *dc)
{
/* Disable interrupts */
atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_XLCDC_LAYER_IDR,
@@ -842,6 +865,15 @@ static void atmel_xlcdc_atomic_disable(struct atmel_hlcdc_plane *plane)
atmel_hlcdc_layer_write_reg(&plane->layer,
ATMEL_XLCDC_LAYER_ENR, 0);
/*
* Updating XLCDC_xxxCFGx, XLCDC_xxxFBA and XLCDC_xxxEN,
* (where xxx indicates each layer) requires writing one to the
* Update Attribute field for each layer in LCDC_ATTRE register for SAM9X7.
*/
regmap_write(dc->hlcdc->regmap, ATMEL_XLCDC_ATTRE, ATMEL_XLCDC_BASE_UPDATE |
ATMEL_XLCDC_OVR1_UPDATE | ATMEL_XLCDC_OVR3_UPDATE |
ATMEL_XLCDC_HEO_UPDATE);
/* Clear all pending interrupts */
atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_XLCDC_LAYER_ISR);
}
@@ -852,7 +884,7 @@ static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
struct atmel_hlcdc_dc *dc = plane->base.dev->dev_private;
dc->desc->ops->lcdc_atomic_disable(plane);
dc->desc->ops->lcdc_atomic_disable(plane, dc);
}
static void atmel_hlcdc_atomic_update(struct atmel_hlcdc_plane *plane,
@@ -1034,7 +1066,7 @@ static void atmel_hlcdc_irq_dbg(struct atmel_hlcdc_plane *plane,
if (isr &
(ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
drm_dbg(plane->base.dev, "overrun on plane %s\n",
desc->name);
}
@@ -1051,7 +1083,7 @@ static void atmel_xlcdc_irq_dbg(struct atmel_hlcdc_plane *plane,
if (isr &
(ATMEL_XLCDC_LAYER_OVR_IRQ(0) | ATMEL_XLCDC_LAYER_OVR_IRQ(1) |
ATMEL_XLCDC_LAYER_OVR_IRQ(2)))
dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
drm_dbg(plane->base.dev, "overrun on plane %s\n",
desc->name);
}
@@ -1140,7 +1172,7 @@ static void atmel_hlcdc_plane_reset(struct drm_plane *p)
if (state) {
if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
kfree(state);
dev_err(p->dev->dev,
drm_err(p->dev,
"Failed to allocate initial plane state\n");
return;
}

View File

@@ -61,6 +61,14 @@ config DRM_DW_HDMI_QP
select DRM_KMS_HELPER
select REGMAP_MMIO
config DRM_DW_HDMI_QP_CEC
bool "Synopsis Designware QP CEC interface"
depends on DRM_DW_HDMI_QP
select DRM_DISPLAY_HDMI_CEC_HELPER
help
Support the CEC interface which is part of the Synopsys
Designware HDMI QP block.
config DRM_DW_MIPI_DSI
tristate
select DRM_KMS_HELPER

View File

@@ -18,6 +18,7 @@
#include <drm/bridge/dw_hdmi_qp.h>
#include <drm/display/drm_hdmi_helper.h>
#include <drm/display/drm_hdmi_cec_helper.h>
#include <drm/display/drm_hdmi_state_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
@@ -26,6 +27,8 @@
#include <drm/drm_edid.h>
#include <drm/drm_modes.h>
#include <media/cec.h>
#include <sound/hdmi-codec.h>
#include "dw-hdmi-qp.h"
@@ -131,17 +134,34 @@ struct dw_hdmi_qp_i2c {
bool is_segment;
};
#ifdef CONFIG_DRM_DW_HDMI_QP_CEC
struct dw_hdmi_qp_cec {
struct drm_connector *connector;
int irq;
u32 addresses;
struct cec_msg rx_msg;
u8 tx_status;
bool tx_done;
bool rx_done;
};
#endif
struct dw_hdmi_qp {
struct drm_bridge bridge;
struct device *dev;
struct dw_hdmi_qp_i2c *i2c;
#ifdef CONFIG_DRM_DW_HDMI_QP_CEC
struct dw_hdmi_qp_cec *cec;
#endif
struct {
const struct dw_hdmi_qp_phy_ops *ops;
void *data;
} phy;
unsigned long ref_clk_rate;
struct regmap *regm;
unsigned long tmds_char_rate;
@@ -965,6 +985,179 @@ static int dw_hdmi_qp_bridge_write_infoframe(struct drm_bridge *bridge,
}
}
#ifdef CONFIG_DRM_DW_HDMI_QP_CEC
static irqreturn_t dw_hdmi_qp_cec_hardirq(int irq, void *dev_id)
{
struct dw_hdmi_qp *hdmi = dev_id;
struct dw_hdmi_qp_cec *cec = hdmi->cec;
irqreturn_t ret = IRQ_HANDLED;
u32 stat;
stat = dw_hdmi_qp_read(hdmi, CEC_INT_STATUS);
if (stat == 0)
return IRQ_NONE;
dw_hdmi_qp_write(hdmi, stat, CEC_INT_CLEAR);
if (stat & CEC_STAT_LINE_ERR) {
cec->tx_status = CEC_TX_STATUS_ERROR;
cec->tx_done = true;
ret = IRQ_WAKE_THREAD;
} else if (stat & CEC_STAT_DONE) {
cec->tx_status = CEC_TX_STATUS_OK;
cec->tx_done = true;
ret = IRQ_WAKE_THREAD;
} else if (stat & CEC_STAT_NACK) {
cec->tx_status = CEC_TX_STATUS_NACK;
cec->tx_done = true;
ret = IRQ_WAKE_THREAD;
}
if (stat & CEC_STAT_EOM) {
unsigned int len, i, val;
val = dw_hdmi_qp_read(hdmi, CEC_RX_COUNT_STATUS);
len = (val & 0xf) + 1;
if (len > sizeof(cec->rx_msg.msg))
len = sizeof(cec->rx_msg.msg);
for (i = 0; i < 4; i++) {
val = dw_hdmi_qp_read(hdmi, CEC_RX_DATA3_0 + i * 4);
cec->rx_msg.msg[i * 4] = val & 0xff;
cec->rx_msg.msg[i * 4 + 1] = (val >> 8) & 0xff;
cec->rx_msg.msg[i * 4 + 2] = (val >> 16) & 0xff;
cec->rx_msg.msg[i * 4 + 3] = (val >> 24) & 0xff;
}
dw_hdmi_qp_write(hdmi, 1, CEC_LOCK_CONTROL);
cec->rx_msg.len = len;
cec->rx_done = true;
ret = IRQ_WAKE_THREAD;
}
return ret;
}
static irqreturn_t dw_hdmi_qp_cec_thread(int irq, void *dev_id)
{
struct dw_hdmi_qp *hdmi = dev_id;
struct dw_hdmi_qp_cec *cec = hdmi->cec;
if (cec->tx_done) {
cec->tx_done = false;
drm_connector_hdmi_cec_transmit_attempt_done(cec->connector,
cec->tx_status);
}
if (cec->rx_done) {
cec->rx_done = false;
drm_connector_hdmi_cec_received_msg(cec->connector, &cec->rx_msg);
}
return IRQ_HANDLED;
}
static int dw_hdmi_qp_cec_init(struct drm_bridge *bridge,
struct drm_connector *connector)
{
struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge);
struct dw_hdmi_qp_cec *cec = hdmi->cec;
cec->connector = connector;
dw_hdmi_qp_write(hdmi, 0, CEC_TX_COUNT);
dw_hdmi_qp_write(hdmi, ~0, CEC_INT_CLEAR);
dw_hdmi_qp_write(hdmi, 0, CEC_INT_MASK_N);
return devm_request_threaded_irq(hdmi->dev, cec->irq,
dw_hdmi_qp_cec_hardirq,
dw_hdmi_qp_cec_thread, IRQF_SHARED,
dev_name(hdmi->dev), hdmi);
}
static int dw_hdmi_qp_cec_log_addr(struct drm_bridge *bridge, u8 logical_addr)
{
struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge);
struct dw_hdmi_qp_cec *cec = hdmi->cec;
if (logical_addr == CEC_LOG_ADDR_INVALID)
cec->addresses = 0;
else
cec->addresses |= BIT(logical_addr) | CEC_ADDR_BROADCAST;
dw_hdmi_qp_write(hdmi, cec->addresses, CEC_ADDR);
return 0;
}
static int dw_hdmi_qp_cec_enable(struct drm_bridge *bridge, bool enable)
{
struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge);
unsigned int irqs;
u32 swdisable;
if (!enable) {
dw_hdmi_qp_write(hdmi, 0, CEC_INT_MASK_N);
dw_hdmi_qp_write(hdmi, ~0, CEC_INT_CLEAR);
swdisable = dw_hdmi_qp_read(hdmi, GLOBAL_SWDISABLE);
swdisable = swdisable | CEC_SWDISABLE;
dw_hdmi_qp_write(hdmi, swdisable, GLOBAL_SWDISABLE);
} else {
swdisable = dw_hdmi_qp_read(hdmi, GLOBAL_SWDISABLE);
swdisable = swdisable & ~CEC_SWDISABLE;
dw_hdmi_qp_write(hdmi, swdisable, GLOBAL_SWDISABLE);
dw_hdmi_qp_write(hdmi, ~0, CEC_INT_CLEAR);
dw_hdmi_qp_write(hdmi, 1, CEC_LOCK_CONTROL);
dw_hdmi_qp_cec_log_addr(bridge, CEC_LOG_ADDR_INVALID);
irqs = CEC_STAT_LINE_ERR | CEC_STAT_NACK | CEC_STAT_EOM |
CEC_STAT_DONE;
dw_hdmi_qp_write(hdmi, ~0, CEC_INT_CLEAR);
dw_hdmi_qp_write(hdmi, irqs, CEC_INT_MASK_N);
}
return 0;
}
static int dw_hdmi_qp_cec_transmit(struct drm_bridge *bridge, u8 attempts,
u32 signal_free_time, struct cec_msg *msg)
{
struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge);
unsigned int i;
u32 val;
for (i = 0; i < msg->len; i++) {
if (!(i % 4))
val = msg->msg[i];
if ((i % 4) == 1)
val |= msg->msg[i] << 8;
if ((i % 4) == 2)
val |= msg->msg[i] << 16;
if ((i % 4) == 3)
val |= msg->msg[i] << 24;
if (i == (msg->len - 1) || (i % 4) == 3)
dw_hdmi_qp_write(hdmi, val, CEC_TX_DATA3_0 + (i / 4) * 4);
}
dw_hdmi_qp_write(hdmi, msg->len - 1, CEC_TX_COUNT);
dw_hdmi_qp_write(hdmi, CEC_CTRL_START, CEC_TX_CONTROL);
return 0;
}
#else
#define dw_hdmi_qp_cec_init NULL
#define dw_hdmi_qp_cec_enable NULL
#define dw_hdmi_qp_cec_log_addr NULL
#define dw_hdmi_qp_cec_transmit NULL
#endif /* CONFIG_DRM_DW_HDMI_QP_CEC */
static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
@@ -979,6 +1172,10 @@ static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
.hdmi_audio_startup = dw_hdmi_qp_audio_enable,
.hdmi_audio_shutdown = dw_hdmi_qp_audio_disable,
.hdmi_audio_prepare = dw_hdmi_qp_audio_prepare,
.hdmi_cec_init = dw_hdmi_qp_cec_init,
.hdmi_cec_enable = dw_hdmi_qp_cec_enable,
.hdmi_cec_log_addr = dw_hdmi_qp_cec_log_addr,
.hdmi_cec_transmit = dw_hdmi_qp_cec_transmit,
};
static irqreturn_t dw_hdmi_qp_main_hardirq(int irq, void *dev_id)
@@ -1014,13 +1211,11 @@ static void dw_hdmi_qp_init_hw(struct dw_hdmi_qp *hdmi)
{
dw_hdmi_qp_write(hdmi, 0, MAINUNIT_0_INT_MASK_N);
dw_hdmi_qp_write(hdmi, 0, MAINUNIT_1_INT_MASK_N);
dw_hdmi_qp_write(hdmi, 428571429, TIMER_BASE_CONFIG0);
dw_hdmi_qp_write(hdmi, hdmi->ref_clk_rate, TIMER_BASE_CONFIG0);
/* Software reset */
dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);
dw_hdmi_qp_write(hdmi, 0x085c085c, I2CM_FM_SCL_CONFIG0);
dw_hdmi_qp_mod(hdmi, 0, I2CM_FM_EN, I2CM_INTERFACE_CONTROL0);
/* Clear DONE and ERROR interrupts */
@@ -1066,6 +1261,13 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
hdmi->phy.ops = plat_data->phy_ops;
hdmi->phy.data = plat_data->phy_data;
if (plat_data->ref_clk_rate) {
hdmi->ref_clk_rate = plat_data->ref_clk_rate;
} else {
hdmi->ref_clk_rate = 428571429;
dev_warn(dev, "Set ref_clk_rate to vendor default\n");
}
dw_hdmi_qp_init_hw(hdmi);
ret = devm_request_threaded_irq(dev, plat_data->main_irq,
@@ -1093,6 +1295,22 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
hdmi->bridge.hdmi_audio_dev = dev;
hdmi->bridge.hdmi_audio_dai_port = 1;
#ifdef CONFIG_DRM_DW_HDMI_QP_CEC
if (plat_data->cec_irq) {
hdmi->bridge.ops |= DRM_BRIDGE_OP_HDMI_CEC_ADAPTER;
hdmi->bridge.hdmi_cec_dev = dev;
hdmi->bridge.hdmi_cec_adapter_name = dev_name(dev);
hdmi->cec = devm_kzalloc(hdmi->dev, sizeof(*hdmi->cec), GFP_KERNEL);
if (!hdmi->cec)
return ERR_PTR(-ENOMEM);
hdmi->cec->irq = plat_data->cec_irq;
} else {
dev_warn(dev, "Disabled CEC support due to missing IRQ\n");
}
#endif
ret = devm_drm_bridge_add(dev, &hdmi->bridge);
if (ret)
return ERR_PTR(ret);

View File

@@ -488,9 +488,23 @@
#define AUDPKT_VBIT_OVR0 0xf24
/* CEC Registers */
#define CEC_TX_CONTROL 0x1000
#define CEC_CTRL_CLEAR BIT(0)
#define CEC_CTRL_START BIT(0)
#define CEC_STATUS 0x1004
#define CEC_STAT_DONE BIT(0)
#define CEC_STAT_NACK BIT(1)
#define CEC_STAT_ARBLOST BIT(2)
#define CEC_STAT_LINE_ERR BIT(3)
#define CEC_STAT_RETRANS_FAIL BIT(4)
#define CEC_STAT_DISCARD BIT(5)
#define CEC_STAT_TX_BUSY BIT(8)
#define CEC_STAT_RX_BUSY BIT(9)
#define CEC_STAT_DRIVE_ERR BIT(10)
#define CEC_STAT_EOM BIT(11)
#define CEC_STAT_NOTIFY_ERR BIT(12)
#define CEC_CONFIG 0x1008
#define CEC_ADDR 0x100c
#define CEC_ADDR_BROADCAST BIT(15)
#define CEC_TX_COUNT 0x1020
#define CEC_TX_DATA3_0 0x1024
#define CEC_TX_DATA7_4 0x1028

View File

@@ -62,26 +62,20 @@ err_drm_err:
return ret;
}
static int drm_fbdev_client_suspend(struct drm_client_dev *client, bool holds_console_lock)
static int drm_fbdev_client_suspend(struct drm_client_dev *client)
{
struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
if (holds_console_lock)
drm_fb_helper_set_suspend(fb_helper, true);
else
drm_fb_helper_set_suspend_unlocked(fb_helper, true);
drm_fb_helper_set_suspend_unlocked(fb_helper, true);
return 0;
}
static int drm_fbdev_client_resume(struct drm_client_dev *client, bool holds_console_lock)
static int drm_fbdev_client_resume(struct drm_client_dev *client)
{
struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
if (holds_console_lock)
drm_fb_helper_set_suspend(fb_helper, false);
else
drm_fb_helper_set_suspend_unlocked(fb_helper, false);
drm_fb_helper_set_suspend_unlocked(fb_helper, false);
return 0;
}

View File

@@ -319,7 +319,7 @@ static int drm_log_client_hotplug(struct drm_client_dev *client)
return 0;
}
static int drm_log_client_suspend(struct drm_client_dev *client, bool _console_lock)
static int drm_log_client_suspend(struct drm_client_dev *client)
{
struct drm_log *dlog = client_to_drm_log(client);
@@ -328,7 +328,7 @@ static int drm_log_client_suspend(struct drm_client_dev *client, bool _console_l
return 0;
}
static int drm_log_client_resume(struct drm_client_dev *client, bool _console_lock)
static int drm_log_client_resume(struct drm_client_dev *client)
{
struct drm_log *dlog = client_to_drm_log(client);

View File

@@ -618,6 +618,20 @@ static const struct drm_connector_hdmi_cec_funcs drm_bridge_connector_hdmi_cec_f
* Bridge Connector Initialisation
*/
static void drm_bridge_connector_put_bridges(struct drm_device *dev, void *data)
{
struct drm_bridge_connector *bridge_connector = (struct drm_bridge_connector *)data;
drm_bridge_put(bridge_connector->bridge_edid);
drm_bridge_put(bridge_connector->bridge_hpd);
drm_bridge_put(bridge_connector->bridge_detect);
drm_bridge_put(bridge_connector->bridge_modes);
drm_bridge_put(bridge_connector->bridge_hdmi);
drm_bridge_put(bridge_connector->bridge_hdmi_audio);
drm_bridge_put(bridge_connector->bridge_dp_audio);
drm_bridge_put(bridge_connector->bridge_hdmi_cec);
}
/**
* drm_bridge_connector_init - Initialise a connector for a chain of bridges
* @drm: the DRM device
@@ -638,7 +652,15 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
struct drm_bridge_connector *bridge_connector;
struct drm_connector *connector;
struct i2c_adapter *ddc = NULL;
struct drm_bridge *panel_bridge = NULL;
struct drm_bridge *panel_bridge __free(drm_bridge_put) = NULL;
struct drm_bridge *bridge_edid __free(drm_bridge_put) = NULL;
struct drm_bridge *bridge_hpd __free(drm_bridge_put) = NULL;
struct drm_bridge *bridge_detect __free(drm_bridge_put) = NULL;
struct drm_bridge *bridge_modes __free(drm_bridge_put) = NULL;
struct drm_bridge *bridge_hdmi __free(drm_bridge_put) = NULL;
struct drm_bridge *bridge_hdmi_audio __free(drm_bridge_put) = NULL;
struct drm_bridge *bridge_dp_audio __free(drm_bridge_put) = NULL;
struct drm_bridge *bridge_hdmi_cec __free(drm_bridge_put) = NULL;
unsigned int supported_formats = BIT(HDMI_COLORSPACE_RGB);
unsigned int max_bpc = 8;
bool support_hdcp = false;
@@ -649,6 +671,10 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
if (!bridge_connector)
return ERR_PTR(-ENOMEM);
ret = drmm_add_action(drm, drm_bridge_connector_put_bridges, bridge_connector);
if (ret)
return ERR_PTR(ret);
bridge_connector->encoder = encoder;
/*
@@ -672,22 +698,30 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
if (!bridge->ycbcr_420_allowed)
connector->ycbcr_420_allowed = false;
if (bridge->ops & DRM_BRIDGE_OP_EDID)
bridge_connector->bridge_edid = bridge;
if (bridge->ops & DRM_BRIDGE_OP_HPD)
bridge_connector->bridge_hpd = bridge;
if (bridge->ops & DRM_BRIDGE_OP_DETECT)
bridge_connector->bridge_detect = bridge;
if (bridge->ops & DRM_BRIDGE_OP_MODES)
bridge_connector->bridge_modes = bridge;
if (bridge->ops & DRM_BRIDGE_OP_EDID) {
drm_bridge_put(bridge_edid);
bridge_edid = drm_bridge_get(bridge);
}
if (bridge->ops & DRM_BRIDGE_OP_HPD) {
drm_bridge_put(bridge_hpd);
bridge_hpd = drm_bridge_get(bridge);
}
if (bridge->ops & DRM_BRIDGE_OP_DETECT) {
drm_bridge_put(bridge_detect);
bridge_detect = drm_bridge_get(bridge);
}
if (bridge->ops & DRM_BRIDGE_OP_MODES) {
drm_bridge_put(bridge_modes);
bridge_modes = drm_bridge_get(bridge);
}
if (bridge->ops & DRM_BRIDGE_OP_HDMI) {
if (bridge_connector->bridge_hdmi)
if (bridge_hdmi)
return ERR_PTR(-EBUSY);
if (!bridge->funcs->hdmi_write_infoframe ||
!bridge->funcs->hdmi_clear_infoframe)
return ERR_PTR(-EINVAL);
bridge_connector->bridge_hdmi = bridge;
bridge_hdmi = drm_bridge_get(bridge);
if (bridge->supported_formats)
supported_formats = bridge->supported_formats;
@@ -696,10 +730,10 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
}
if (bridge->ops & DRM_BRIDGE_OP_HDMI_AUDIO) {
if (bridge_connector->bridge_hdmi_audio)
if (bridge_hdmi_audio)
return ERR_PTR(-EBUSY);
if (bridge_connector->bridge_dp_audio)
if (bridge_dp_audio)
return ERR_PTR(-EBUSY);
if (!bridge->hdmi_audio_max_i2s_playback_channels &&
@@ -710,14 +744,14 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
!bridge->funcs->hdmi_audio_shutdown)
return ERR_PTR(-EINVAL);
bridge_connector->bridge_hdmi_audio = bridge;
bridge_hdmi_audio = drm_bridge_get(bridge);
}
if (bridge->ops & DRM_BRIDGE_OP_DP_AUDIO) {
if (bridge_connector->bridge_dp_audio)
if (bridge_dp_audio)
return ERR_PTR(-EBUSY);
if (bridge_connector->bridge_hdmi_audio)
if (bridge_hdmi_audio)
return ERR_PTR(-EBUSY);
if (!bridge->hdmi_audio_max_i2s_playback_channels &&
@@ -728,7 +762,7 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
!bridge->funcs->dp_audio_shutdown)
return ERR_PTR(-EINVAL);
bridge_connector->bridge_dp_audio = bridge;
bridge_dp_audio = drm_bridge_get(bridge);
}
if (bridge->ops & DRM_BRIDGE_OP_HDMI_CEC_NOTIFIER) {
@@ -739,10 +773,10 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
}
if (bridge->ops & DRM_BRIDGE_OP_HDMI_CEC_ADAPTER) {
if (bridge_connector->bridge_hdmi_cec)
if (bridge_hdmi_cec)
return ERR_PTR(-EBUSY);
bridge_connector->bridge_hdmi_cec = bridge;
bridge_hdmi_cec = drm_bridge_get(bridge);
if (!bridge->funcs->hdmi_cec_enable ||
!bridge->funcs->hdmi_cec_log_addr ||
@@ -762,7 +796,7 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
ddc = bridge->ddc;
if (drm_bridge_is_panel(bridge))
panel_bridge = bridge;
panel_bridge = drm_bridge_get(bridge);
if (bridge->support_hdcp)
support_hdcp = true;
@@ -771,13 +805,13 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
if (connector_type == DRM_MODE_CONNECTOR_Unknown)
return ERR_PTR(-EINVAL);
if (bridge_connector->bridge_hdmi) {
if (bridge_hdmi) {
if (!connector->ycbcr_420_allowed)
supported_formats &= ~BIT(HDMI_COLORSPACE_YUV420);
ret = drmm_connector_hdmi_init(drm, connector,
bridge_connector->bridge_hdmi->vendor,
bridge_connector->bridge_hdmi->product,
bridge_hdmi->vendor,
bridge_hdmi->product,
&drm_bridge_connector_funcs,
&drm_bridge_connector_hdmi_funcs,
connector_type, ddc,
@@ -793,15 +827,14 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
return ERR_PTR(ret);
}
if (bridge_connector->bridge_hdmi_audio ||
bridge_connector->bridge_dp_audio) {
if (bridge_hdmi_audio || bridge_dp_audio) {
struct device *dev;
struct drm_bridge *bridge;
if (bridge_connector->bridge_hdmi_audio)
bridge = bridge_connector->bridge_hdmi_audio;
if (bridge_hdmi_audio)
bridge = bridge_hdmi_audio;
else
bridge = bridge_connector->bridge_dp_audio;
bridge = bridge_dp_audio;
dev = bridge->hdmi_audio_dev;
@@ -815,9 +848,9 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
return ERR_PTR(ret);
}
if (bridge_connector->bridge_hdmi_cec &&
bridge_connector->bridge_hdmi_cec->ops & DRM_BRIDGE_OP_HDMI_CEC_NOTIFIER) {
struct drm_bridge *bridge = bridge_connector->bridge_hdmi_cec;
if (bridge_hdmi_cec &&
bridge_hdmi_cec->ops & DRM_BRIDGE_OP_HDMI_CEC_NOTIFIER) {
struct drm_bridge *bridge = bridge_hdmi_cec;
ret = drmm_connector_hdmi_cec_notifier_register(connector,
NULL,
@@ -826,9 +859,9 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
return ERR_PTR(ret);
}
if (bridge_connector->bridge_hdmi_cec &&
bridge_connector->bridge_hdmi_cec->ops & DRM_BRIDGE_OP_HDMI_CEC_ADAPTER) {
struct drm_bridge *bridge = bridge_connector->bridge_hdmi_cec;
if (bridge_hdmi_cec &&
bridge_hdmi_cec->ops & DRM_BRIDGE_OP_HDMI_CEC_ADAPTER) {
struct drm_bridge *bridge = bridge_hdmi_cec;
ret = drmm_connector_hdmi_cec_register(connector,
&drm_bridge_connector_hdmi_cec_funcs,
@@ -841,9 +874,9 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
drm_connector_helper_add(connector, &drm_bridge_connector_helper_funcs);
if (bridge_connector->bridge_hpd)
if (bridge_hpd)
connector->polled = DRM_CONNECTOR_POLL_HPD;
else if (bridge_connector->bridge_detect)
else if (bridge_detect)
connector->polled = DRM_CONNECTOR_POLL_CONNECT
| DRM_CONNECTOR_POLL_DISCONNECT;
@@ -854,6 +887,15 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
IS_ENABLED(CONFIG_DRM_DISPLAY_HDCP_HELPER))
drm_connector_attach_content_protection_property(connector, true);
bridge_connector->bridge_edid = drm_bridge_get(bridge_edid);
bridge_connector->bridge_hpd = drm_bridge_get(bridge_hpd);
bridge_connector->bridge_detect = drm_bridge_get(bridge_detect);
bridge_connector->bridge_modes = drm_bridge_get(bridge_modes);
bridge_connector->bridge_hdmi = drm_bridge_get(bridge_hdmi);
bridge_connector->bridge_hdmi_audio = drm_bridge_get(bridge_hdmi_audio);
bridge_connector->bridge_dp_audio = drm_bridge_get(bridge_dp_audio);
bridge_connector->bridge_hdmi_cec = drm_bridge_get(bridge_hdmi_cec);
return connector;
}
EXPORT_SYMBOL_GPL(drm_bridge_connector_init);

View File

@@ -207,9 +207,9 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
continue;
connector->funcs->atomic_destroy_state(connector,
state->connectors[i].state);
state->connectors[i].state_to_destroy);
state->connectors[i].ptr = NULL;
state->connectors[i].state = NULL;
state->connectors[i].state_to_destroy = NULL;
state->connectors[i].old_state = NULL;
state->connectors[i].new_state = NULL;
drm_connector_put(connector);
@@ -222,10 +222,10 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
continue;
crtc->funcs->atomic_destroy_state(crtc,
state->crtcs[i].state);
state->crtcs[i].state_to_destroy);
state->crtcs[i].ptr = NULL;
state->crtcs[i].state = NULL;
state->crtcs[i].state_to_destroy = NULL;
state->crtcs[i].old_state = NULL;
state->crtcs[i].new_state = NULL;
@@ -242,9 +242,9 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
continue;
plane->funcs->atomic_destroy_state(plane,
state->planes[i].state);
state->planes[i].state_to_destroy);
state->planes[i].ptr = NULL;
state->planes[i].state = NULL;
state->planes[i].state_to_destroy = NULL;
state->planes[i].old_state = NULL;
state->planes[i].new_state = NULL;
}
@@ -253,9 +253,9 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
struct drm_private_obj *obj = state->private_objs[i].ptr;
obj->funcs->atomic_destroy_state(obj,
state->private_objs[i].state);
state->private_objs[i].state_to_destroy);
state->private_objs[i].ptr = NULL;
state->private_objs[i].state = NULL;
state->private_objs[i].state_to_destroy = NULL;
state->private_objs[i].old_state = NULL;
state->private_objs[i].new_state = NULL;
}
@@ -349,7 +349,7 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state,
WARN_ON(!state->acquire_ctx);
crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
if (crtc_state)
return crtc_state;
@@ -361,7 +361,7 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state,
if (!crtc_state)
return ERR_PTR(-ENOMEM);
state->crtcs[index].state = crtc_state;
state->crtcs[index].state_to_destroy = crtc_state;
state->crtcs[index].old_state = crtc->state;
state->crtcs[index].new_state = crtc_state;
state->crtcs[index].ptr = crtc;
@@ -480,8 +480,8 @@ static int drm_atomic_connector_check(struct drm_connector *connector,
}
if (state->crtc)
crtc_state = drm_atomic_get_existing_crtc_state(state->state,
state->crtc);
crtc_state = drm_atomic_get_new_crtc_state(state->state,
state->crtc);
if (writeback_job->fb && !crtc_state->active) {
drm_dbg_atomic(connector->dev,
@@ -534,7 +534,7 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state,
WARN_ON(plane->old_fb);
WARN_ON(plane->crtc);
plane_state = drm_atomic_get_existing_plane_state(state, plane);
plane_state = drm_atomic_get_new_plane_state(state, plane);
if (plane_state)
return plane_state;
@@ -546,7 +546,7 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state,
if (!plane_state)
return ERR_PTR(-ENOMEM);
state->planes[index].state = plane_state;
state->planes[index].state_to_destroy = plane_state;
state->planes[index].ptr = plane;
state->planes[index].old_state = plane->state;
state->planes[index].new_state = plane_state;
@@ -831,14 +831,14 @@ struct drm_private_state *
drm_atomic_get_private_obj_state(struct drm_atomic_state *state,
struct drm_private_obj *obj)
{
int index, num_objs, i, ret;
int index, num_objs, ret;
size_t size;
struct __drm_private_objs_state *arr;
struct drm_private_state *obj_state;
for (i = 0; i < state->num_private_objs; i++)
if (obj == state->private_objs[i].ptr)
return state->private_objs[i].state;
obj_state = drm_atomic_get_new_private_obj_state(state, obj);
if (obj_state)
return obj_state;
ret = drm_modeset_lock(&obj->lock, state->acquire_ctx);
if (ret)
@@ -858,7 +858,7 @@ drm_atomic_get_private_obj_state(struct drm_atomic_state *state,
if (!obj_state)
return ERR_PTR(-ENOMEM);
state->private_objs[index].state = obj_state;
state->private_objs[index].state_to_destroy = obj_state;
state->private_objs[index].old_state = obj->state;
state->private_objs[index].new_state = obj_state;
state->private_objs[index].ptr = obj;
@@ -1152,15 +1152,16 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
state->num_connector = alloc;
}
if (state->connectors[index].state)
return state->connectors[index].state;
connector_state = drm_atomic_get_new_connector_state(state, connector);
if (connector_state)
return connector_state;
connector_state = connector->funcs->atomic_duplicate_state(connector);
if (!connector_state)
return ERR_PTR(-ENOMEM);
drm_connector_get(connector);
state->connectors[index].state = connector_state;
state->connectors[index].state_to_destroy = connector_state;
state->connectors[index].old_state = connector->state;
state->connectors[index].new_state = connector_state;
state->connectors[index].ptr = connector;

View File

@@ -3236,7 +3236,7 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state,
old_conn_state->state = state;
new_conn_state->state = NULL;
state->connectors[i].state = old_conn_state;
state->connectors[i].state_to_destroy = old_conn_state;
connector->state = new_conn_state;
}
@@ -3246,7 +3246,7 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state,
old_crtc_state->state = state;
new_crtc_state->state = NULL;
state->crtcs[i].state = old_crtc_state;
state->crtcs[i].state_to_destroy = old_crtc_state;
crtc->state = new_crtc_state;
if (new_crtc_state->commit) {
@@ -3266,7 +3266,7 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state,
old_plane_state->state = state;
new_plane_state->state = NULL;
state->planes[i].state = old_plane_state;
state->planes[i].state_to_destroy = old_plane_state;
plane->state = new_plane_state;
}
drm_panic_unlock(state->dev, flags);
@@ -3277,7 +3277,7 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state,
old_obj_state->state = state;
new_obj_state->state = NULL;
state->private_objs[i].state = old_obj_state;
state->private_objs[i].state_to_destroy = old_obj_state;
obj->state = new_obj_state;
}

View File

@@ -1086,12 +1086,12 @@ drm_atomic_bridge_chain_select_bus_fmts(struct drm_bridge *bridge,
struct drm_encoder *encoder = bridge->encoder;
struct drm_bridge_state *last_bridge_state;
unsigned int i, num_out_bus_fmts = 0;
struct drm_bridge *last_bridge;
u32 *out_bus_fmts;
int ret = 0;
last_bridge = list_last_entry(&encoder->bridge_chain,
struct drm_bridge, chain_node);
struct drm_bridge *last_bridge __free(drm_bridge_put) =
drm_bridge_get(list_last_entry(&encoder->bridge_chain,
struct drm_bridge, chain_node));
last_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state,
last_bridge);

View File

@@ -12,8 +12,17 @@
#include <drm/drm_buddy.h>
enum drm_buddy_free_tree {
DRM_BUDDY_CLEAR_TREE = 0,
DRM_BUDDY_DIRTY_TREE,
DRM_BUDDY_MAX_FREE_TREES,
};
static struct kmem_cache *slab_blocks;
#define for_each_free_tree(tree) \
for ((tree) = 0; (tree) < DRM_BUDDY_MAX_FREE_TREES; (tree)++)
static struct drm_buddy_block *drm_block_alloc(struct drm_buddy *mm,
struct drm_buddy_block *parent,
unsigned int order,
@@ -31,6 +40,8 @@ static struct drm_buddy_block *drm_block_alloc(struct drm_buddy *mm,
block->header |= order;
block->parent = parent;
RB_CLEAR_NODE(&block->rb);
BUG_ON(block->header & DRM_BUDDY_HEADER_UNUSED);
return block;
}
@@ -41,23 +52,64 @@ static void drm_block_free(struct drm_buddy *mm,
kmem_cache_free(slab_blocks, block);
}
static void list_insert_sorted(struct drm_buddy *mm,
struct drm_buddy_block *block)
static enum drm_buddy_free_tree
get_block_tree(struct drm_buddy_block *block)
{
struct drm_buddy_block *node;
struct list_head *head;
return drm_buddy_block_is_clear(block) ?
DRM_BUDDY_CLEAR_TREE : DRM_BUDDY_DIRTY_TREE;
}
head = &mm->free_list[drm_buddy_block_order(block)];
if (list_empty(head)) {
list_add(&block->link, head);
return;
}
static struct drm_buddy_block *
rbtree_get_free_block(const struct rb_node *node)
{
return node ? rb_entry(node, struct drm_buddy_block, rb) : NULL;
}
list_for_each_entry(node, head, link)
if (drm_buddy_block_offset(block) < drm_buddy_block_offset(node))
break;
static struct drm_buddy_block *
rbtree_last_free_block(struct rb_root *root)
{
return rbtree_get_free_block(rb_last(root));
}
__list_add(&block->link, node->link.prev, &node->link);
static bool rbtree_is_empty(struct rb_root *root)
{
return RB_EMPTY_ROOT(root);
}
static bool drm_buddy_block_offset_less(const struct drm_buddy_block *block,
const struct drm_buddy_block *node)
{
return drm_buddy_block_offset(block) < drm_buddy_block_offset(node);
}
static bool rbtree_block_offset_less(struct rb_node *block,
const struct rb_node *node)
{
return drm_buddy_block_offset_less(rbtree_get_free_block(block),
rbtree_get_free_block(node));
}
static void rbtree_insert(struct drm_buddy *mm,
struct drm_buddy_block *block,
enum drm_buddy_free_tree tree)
{
rb_add(&block->rb,
&mm->free_trees[tree][drm_buddy_block_order(block)],
rbtree_block_offset_less);
}
static void rbtree_remove(struct drm_buddy *mm,
struct drm_buddy_block *block)
{
unsigned int order = drm_buddy_block_order(block);
enum drm_buddy_free_tree tree;
struct rb_root *root;
tree = get_block_tree(block);
root = &mm->free_trees[tree][order];
rb_erase(&block->rb, root);
RB_CLEAR_NODE(&block->rb);
}
static void clear_reset(struct drm_buddy_block *block)
@@ -70,29 +122,34 @@ static void mark_cleared(struct drm_buddy_block *block)
block->header |= DRM_BUDDY_HEADER_CLEAR;
}
static void mark_allocated(struct drm_buddy_block *block)
static void mark_allocated(struct drm_buddy *mm,
struct drm_buddy_block *block)
{
block->header &= ~DRM_BUDDY_HEADER_STATE;
block->header |= DRM_BUDDY_ALLOCATED;
list_del(&block->link);
rbtree_remove(mm, block);
}
static void mark_free(struct drm_buddy *mm,
struct drm_buddy_block *block)
{
enum drm_buddy_free_tree tree;
block->header &= ~DRM_BUDDY_HEADER_STATE;
block->header |= DRM_BUDDY_FREE;
list_insert_sorted(mm, block);
tree = get_block_tree(block);
rbtree_insert(mm, block, tree);
}
static void mark_split(struct drm_buddy_block *block)
static void mark_split(struct drm_buddy *mm,
struct drm_buddy_block *block)
{
block->header &= ~DRM_BUDDY_HEADER_STATE;
block->header |= DRM_BUDDY_SPLIT;
list_del(&block->link);
rbtree_remove(mm, block);
}
static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2)
@@ -148,7 +205,7 @@ static unsigned int __drm_buddy_free(struct drm_buddy *mm,
mark_cleared(parent);
}
list_del(&buddy->link);
rbtree_remove(mm, buddy);
if (force_merge && drm_buddy_block_is_clear(buddy))
mm->clear_avail -= drm_buddy_block_size(mm, buddy);
@@ -169,7 +226,7 @@ static int __force_merge(struct drm_buddy *mm,
u64 end,
unsigned int min_order)
{
unsigned int order;
unsigned int tree, order;
int i;
if (!min_order)
@@ -178,44 +235,48 @@ static int __force_merge(struct drm_buddy *mm,
if (min_order > mm->max_order)
return -EINVAL;
for (i = min_order - 1; i >= 0; i--) {
struct drm_buddy_block *block, *prev;
for_each_free_tree(tree) {
for (i = min_order - 1; i >= 0; i--) {
struct rb_node *iter = rb_last(&mm->free_trees[tree][i]);
list_for_each_entry_safe_reverse(block, prev, &mm->free_list[i], link) {
struct drm_buddy_block *buddy;
u64 block_start, block_end;
while (iter) {
struct drm_buddy_block *block, *buddy;
u64 block_start, block_end;
if (!block->parent)
continue;
block = rbtree_get_free_block(iter);
iter = rb_prev(iter);
block_start = drm_buddy_block_offset(block);
block_end = block_start + drm_buddy_block_size(mm, block) - 1;
if (!block || !block->parent)
continue;
if (!contains(start, end, block_start, block_end))
continue;
block_start = drm_buddy_block_offset(block);
block_end = block_start + drm_buddy_block_size(mm, block) - 1;
buddy = __get_buddy(block);
if (!drm_buddy_block_is_free(buddy))
continue;
if (!contains(start, end, block_start, block_end))
continue;
WARN_ON(drm_buddy_block_is_clear(block) ==
drm_buddy_block_is_clear(buddy));
buddy = __get_buddy(block);
if (!drm_buddy_block_is_free(buddy))
continue;
/*
* If the prev block is same as buddy, don't access the
* block in the next iteration as we would free the
* buddy block as part of the free function.
*/
if (prev == buddy)
prev = list_prev_entry(prev, link);
WARN_ON(drm_buddy_block_is_clear(block) ==
drm_buddy_block_is_clear(buddy));
list_del(&block->link);
if (drm_buddy_block_is_clear(block))
mm->clear_avail -= drm_buddy_block_size(mm, block);
/*
* Advance to the next node when the current node is the buddy,
* as freeing the block will also remove its buddy from the tree.
*/
if (iter == &buddy->rb)
iter = rb_prev(iter);
order = __drm_buddy_free(mm, block, true);
if (order >= min_order)
return 0;
rbtree_remove(mm, block);
if (drm_buddy_block_is_clear(block))
mm->clear_avail -= drm_buddy_block_size(mm, block);
order = __drm_buddy_free(mm, block, true);
if (order >= min_order)
return 0;
}
}
}
@@ -236,8 +297,8 @@ static int __force_merge(struct drm_buddy *mm,
*/
int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size)
{
unsigned int i;
u64 offset;
unsigned int i, j, root_count = 0;
u64 offset = 0;
if (size < chunk_size)
return -EINVAL;
@@ -258,14 +319,22 @@ int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size)
BUG_ON(mm->max_order > DRM_BUDDY_MAX_ORDER);
mm->free_list = kmalloc_array(mm->max_order + 1,
sizeof(struct list_head),
GFP_KERNEL);
if (!mm->free_list)
mm->free_trees = kmalloc_array(DRM_BUDDY_MAX_FREE_TREES,
sizeof(*mm->free_trees),
GFP_KERNEL);
if (!mm->free_trees)
return -ENOMEM;
for (i = 0; i <= mm->max_order; ++i)
INIT_LIST_HEAD(&mm->free_list[i]);
for_each_free_tree(i) {
mm->free_trees[i] = kmalloc_array(mm->max_order + 1,
sizeof(struct rb_root),
GFP_KERNEL);
if (!mm->free_trees[i])
goto out_free_tree;
for (j = 0; j <= mm->max_order; ++j)
mm->free_trees[i][j] = RB_ROOT;
}
mm->n_roots = hweight64(size);
@@ -273,10 +342,7 @@ int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size)
sizeof(struct drm_buddy_block *),
GFP_KERNEL);
if (!mm->roots)
goto out_free_list;
offset = 0;
i = 0;
goto out_free_tree;
/*
* Split into power-of-two blocks, in case we are given a size that is
@@ -296,24 +362,26 @@ int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size)
mark_free(mm, root);
BUG_ON(i > mm->max_order);
BUG_ON(root_count > mm->max_order);
BUG_ON(drm_buddy_block_size(mm, root) < chunk_size);
mm->roots[i] = root;
mm->roots[root_count] = root;
offset += root_size;
size -= root_size;
i++;
root_count++;
} while (size);
return 0;
out_free_roots:
while (i--)
drm_block_free(mm, mm->roots[i]);
while (root_count--)
drm_block_free(mm, mm->roots[root_count]);
kfree(mm->roots);
out_free_list:
kfree(mm->free_list);
out_free_tree:
while (i--)
kfree(mm->free_trees[i]);
kfree(mm->free_trees);
return -ENOMEM;
}
EXPORT_SYMBOL(drm_buddy_init);
@@ -323,7 +391,7 @@ EXPORT_SYMBOL(drm_buddy_init);
*
* @mm: DRM buddy manager to free
*
* Cleanup memory manager resources and the freelist
* Cleanup memory manager resources and the freetree
*/
void drm_buddy_fini(struct drm_buddy *mm)
{
@@ -349,8 +417,9 @@ void drm_buddy_fini(struct drm_buddy *mm)
WARN_ON(mm->avail != mm->size);
for_each_free_tree(i)
kfree(mm->free_trees[i]);
kfree(mm->roots);
kfree(mm->free_list);
}
EXPORT_SYMBOL(drm_buddy_fini);
@@ -374,8 +443,7 @@ static int split_block(struct drm_buddy *mm,
return -ENOMEM;
}
mark_free(mm, block->left);
mark_free(mm, block->right);
mark_split(mm, block);
if (drm_buddy_block_is_clear(block)) {
mark_cleared(block->left);
@@ -383,7 +451,8 @@ static int split_block(struct drm_buddy *mm,
clear_reset(block);
}
mark_split(block);
mark_free(mm, block->left);
mark_free(mm, block->right);
return 0;
}
@@ -412,10 +481,11 @@ EXPORT_SYMBOL(drm_get_buddy);
* @is_clear: blocks clear state
*
* Reset the clear state based on @is_clear value for each block
* in the freelist.
* in the freetree.
*/
void drm_buddy_reset_clear(struct drm_buddy *mm, bool is_clear)
{
enum drm_buddy_free_tree src_tree, dst_tree;
u64 root_size, size, start;
unsigned int order;
int i;
@@ -430,19 +500,24 @@ void drm_buddy_reset_clear(struct drm_buddy *mm, bool is_clear)
size -= root_size;
}
for (i = 0; i <= mm->max_order; ++i) {
struct drm_buddy_block *block;
src_tree = is_clear ? DRM_BUDDY_DIRTY_TREE : DRM_BUDDY_CLEAR_TREE;
dst_tree = is_clear ? DRM_BUDDY_CLEAR_TREE : DRM_BUDDY_DIRTY_TREE;
list_for_each_entry_reverse(block, &mm->free_list[i], link) {
if (is_clear != drm_buddy_block_is_clear(block)) {
if (is_clear) {
mark_cleared(block);
mm->clear_avail += drm_buddy_block_size(mm, block);
} else {
clear_reset(block);
mm->clear_avail -= drm_buddy_block_size(mm, block);
}
for (i = 0; i <= mm->max_order; ++i) {
struct rb_root *root = &mm->free_trees[src_tree][i];
struct drm_buddy_block *block, *tmp;
rbtree_postorder_for_each_entry_safe(block, tmp, root, rb) {
rbtree_remove(mm, block);
if (is_clear) {
mark_cleared(block);
mm->clear_avail += drm_buddy_block_size(mm, block);
} else {
clear_reset(block);
mm->clear_avail -= drm_buddy_block_size(mm, block);
}
rbtree_insert(mm, block, dst_tree);
}
}
}
@@ -632,23 +707,17 @@ __drm_buddy_alloc_range_bias(struct drm_buddy *mm,
}
static struct drm_buddy_block *
get_maxblock(struct drm_buddy *mm, unsigned int order,
unsigned long flags)
get_maxblock(struct drm_buddy *mm,
unsigned int order,
enum drm_buddy_free_tree tree)
{
struct drm_buddy_block *max_block = NULL, *block = NULL;
struct rb_root *root;
unsigned int i;
for (i = order; i <= mm->max_order; ++i) {
struct drm_buddy_block *tmp_block;
list_for_each_entry_reverse(tmp_block, &mm->free_list[i], link) {
if (block_incompatible(tmp_block, flags))
continue;
block = tmp_block;
break;
}
root = &mm->free_trees[tree][i];
block = rbtree_last_free_block(root);
if (!block)
continue;
@@ -667,46 +736,44 @@ get_maxblock(struct drm_buddy *mm, unsigned int order,
}
static struct drm_buddy_block *
alloc_from_freelist(struct drm_buddy *mm,
alloc_from_freetree(struct drm_buddy *mm,
unsigned int order,
unsigned long flags)
{
struct drm_buddy_block *block = NULL;
struct rb_root *root;
enum drm_buddy_free_tree tree;
unsigned int tmp;
int err;
tree = (flags & DRM_BUDDY_CLEAR_ALLOCATION) ?
DRM_BUDDY_CLEAR_TREE : DRM_BUDDY_DIRTY_TREE;
if (flags & DRM_BUDDY_TOPDOWN_ALLOCATION) {
block = get_maxblock(mm, order, flags);
block = get_maxblock(mm, order, tree);
if (block)
/* Store the obtained block order */
tmp = drm_buddy_block_order(block);
} else {
for (tmp = order; tmp <= mm->max_order; ++tmp) {
struct drm_buddy_block *tmp_block;
list_for_each_entry_reverse(tmp_block, &mm->free_list[tmp], link) {
if (block_incompatible(tmp_block, flags))
continue;
block = tmp_block;
break;
}
/* Get RB tree root for this order and tree */
root = &mm->free_trees[tree][tmp];
block = rbtree_last_free_block(root);
if (block)
break;
}
}
if (!block) {
/* Fallback method */
/* Try allocating from the other tree */
tree = (tree == DRM_BUDDY_CLEAR_TREE) ?
DRM_BUDDY_DIRTY_TREE : DRM_BUDDY_CLEAR_TREE;
for (tmp = order; tmp <= mm->max_order; ++tmp) {
if (!list_empty(&mm->free_list[tmp])) {
block = list_last_entry(&mm->free_list[tmp],
struct drm_buddy_block,
link);
if (block)
break;
}
root = &mm->free_trees[tree][tmp];
block = rbtree_last_free_block(root);
if (block)
break;
}
if (!block)
@@ -771,7 +838,7 @@ static int __alloc_range(struct drm_buddy *mm,
if (contains(start, end, block_start, block_end)) {
if (drm_buddy_block_is_free(block)) {
mark_allocated(block);
mark_allocated(mm, block);
total_allocated += drm_buddy_block_size(mm, block);
mm->avail -= drm_buddy_block_size(mm, block);
if (drm_buddy_block_is_clear(block))
@@ -849,10 +916,9 @@ static int __alloc_contig_try_harder(struct drm_buddy *mm,
{
u64 rhs_offset, lhs_offset, lhs_size, filled;
struct drm_buddy_block *block;
struct list_head *list;
unsigned int tree, order;
LIST_HEAD(blocks_lhs);
unsigned long pages;
unsigned int order;
u64 modify_size;
int err;
@@ -862,35 +928,45 @@ static int __alloc_contig_try_harder(struct drm_buddy *mm,
if (order == 0)
return -ENOSPC;
list = &mm->free_list[order];
if (list_empty(list))
return -ENOSPC;
for_each_free_tree(tree) {
struct rb_root *root;
struct rb_node *iter;
list_for_each_entry_reverse(block, list, link) {
/* Allocate blocks traversing RHS */
rhs_offset = drm_buddy_block_offset(block);
err = __drm_buddy_alloc_range(mm, rhs_offset, size,
&filled, blocks);
if (!err || err != -ENOSPC)
return err;
root = &mm->free_trees[tree][order];
if (rbtree_is_empty(root))
continue;
lhs_size = max((size - filled), min_block_size);
if (!IS_ALIGNED(lhs_size, min_block_size))
lhs_size = round_up(lhs_size, min_block_size);
iter = rb_last(root);
while (iter) {
block = rbtree_get_free_block(iter);
/* Allocate blocks traversing LHS */
lhs_offset = drm_buddy_block_offset(block) - lhs_size;
err = __drm_buddy_alloc_range(mm, lhs_offset, lhs_size,
NULL, &blocks_lhs);
if (!err) {
list_splice(&blocks_lhs, blocks);
return 0;
} else if (err != -ENOSPC) {
/* Allocate blocks traversing RHS */
rhs_offset = drm_buddy_block_offset(block);
err = __drm_buddy_alloc_range(mm, rhs_offset, size,
&filled, blocks);
if (!err || err != -ENOSPC)
return err;
lhs_size = max((size - filled), min_block_size);
if (!IS_ALIGNED(lhs_size, min_block_size))
lhs_size = round_up(lhs_size, min_block_size);
/* Allocate blocks traversing LHS */
lhs_offset = drm_buddy_block_offset(block) - lhs_size;
err = __drm_buddy_alloc_range(mm, lhs_offset, lhs_size,
NULL, &blocks_lhs);
if (!err) {
list_splice(&blocks_lhs, blocks);
return 0;
} else if (err != -ENOSPC) {
drm_buddy_free_list_internal(mm, blocks);
return err;
}
/* Free blocks for the next iteration */
drm_buddy_free_list_internal(mm, blocks);
return err;
iter = rb_prev(iter);
}
/* Free blocks for the next iteration */
drm_buddy_free_list_internal(mm, blocks);
}
return -ENOSPC;
@@ -976,7 +1052,7 @@ int drm_buddy_block_trim(struct drm_buddy *mm,
list_add(&block->tmp_link, &dfs);
err = __alloc_range(mm, &dfs, new_start, new_size, blocks, NULL);
if (err) {
mark_allocated(block);
mark_allocated(mm, block);
mm->avail -= drm_buddy_block_size(mm, block);
if (drm_buddy_block_is_clear(block))
mm->clear_avail -= drm_buddy_block_size(mm, block);
@@ -999,8 +1075,8 @@ __drm_buddy_alloc_blocks(struct drm_buddy *mm,
return __drm_buddy_alloc_range_bias(mm, start, end,
order, flags);
else
/* Allocate from freelist */
return alloc_from_freelist(mm, order, flags);
/* Allocate from freetree */
return alloc_from_freetree(mm, order, flags);
}
/**
@@ -1017,8 +1093,8 @@ __drm_buddy_alloc_blocks(struct drm_buddy *mm,
* alloc_range_bias() called on range limitations, which traverses
* the tree and returns the desired block.
*
* alloc_from_freelist() called when *no* range restrictions
* are enforced, which picks the block from the freelist.
* alloc_from_freetree() called when *no* range restrictions
* are enforced, which picks the block from the freetree.
*
* Returns:
* 0 on success, error code on failure.
@@ -1120,7 +1196,7 @@ int drm_buddy_alloc_blocks(struct drm_buddy *mm,
}
} while (1);
mark_allocated(block);
mark_allocated(mm, block);
mm->avail -= drm_buddy_block_size(mm, block);
if (drm_buddy_block_is_clear(block))
mm->clear_avail -= drm_buddy_block_size(mm, block);
@@ -1201,12 +1277,18 @@ void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p)
mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20, mm->clear_avail >> 20);
for (order = mm->max_order; order >= 0; order--) {
struct drm_buddy_block *block;
struct drm_buddy_block *block, *tmp;
struct rb_root *root;
u64 count = 0, free;
unsigned int tree;
list_for_each_entry(block, &mm->free_list[order], link) {
BUG_ON(!drm_buddy_block_is_free(block));
count++;
for_each_free_tree(tree) {
root = &mm->free_trees[tree][order];
rbtree_postorder_for_each_entry_safe(block, tmp, root, rb) {
BUG_ON(!drm_buddy_block_is_free(block));
count++;
}
}
drm_printf(p, "order-%2d ", order);

View File

@@ -122,7 +122,7 @@ void drm_client_dev_restore(struct drm_device *dev)
mutex_unlock(&dev->clientlist_mutex);
}
static int drm_client_suspend(struct drm_client_dev *client, bool holds_console_lock)
static int drm_client_suspend(struct drm_client_dev *client)
{
struct drm_device *dev = client->dev;
int ret = 0;
@@ -131,7 +131,7 @@ static int drm_client_suspend(struct drm_client_dev *client, bool holds_console_
return 0;
if (client->funcs && client->funcs->suspend)
ret = client->funcs->suspend(client, holds_console_lock);
ret = client->funcs->suspend(client);
drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret);
client->suspended = true;
@@ -139,20 +139,20 @@ static int drm_client_suspend(struct drm_client_dev *client, bool holds_console_
return ret;
}
void drm_client_dev_suspend(struct drm_device *dev, bool holds_console_lock)
void drm_client_dev_suspend(struct drm_device *dev)
{
struct drm_client_dev *client;
mutex_lock(&dev->clientlist_mutex);
list_for_each_entry(client, &dev->clientlist, list) {
if (!client->suspended)
drm_client_suspend(client, holds_console_lock);
drm_client_suspend(client);
}
mutex_unlock(&dev->clientlist_mutex);
}
EXPORT_SYMBOL(drm_client_dev_suspend);
static int drm_client_resume(struct drm_client_dev *client, bool holds_console_lock)
static int drm_client_resume(struct drm_client_dev *client)
{
struct drm_device *dev = client->dev;
int ret = 0;
@@ -161,7 +161,7 @@ static int drm_client_resume(struct drm_client_dev *client, bool holds_console_l
return 0;
if (client->funcs && client->funcs->resume)
ret = client->funcs->resume(client, holds_console_lock);
ret = client->funcs->resume(client);
drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret);
client->suspended = false;
@@ -172,14 +172,14 @@ static int drm_client_resume(struct drm_client_dev *client, bool holds_console_l
return ret;
}
void drm_client_dev_resume(struct drm_device *dev, bool holds_console_lock)
void drm_client_dev_resume(struct drm_device *dev)
{
struct drm_client_dev *client;
mutex_lock(&dev->clientlist_mutex);
list_for_each_entry(client, &dev->clientlist, list) {
if (client->suspended)
drm_client_resume(client, holds_console_lock);
drm_client_resume(client);
}
mutex_unlock(&dev->clientlist_mutex);
}

View File

@@ -1048,7 +1048,7 @@ retry:
plane_state->crtc->base.id,
plane_state->crtc->name, fb->base.id);
crtc_state = drm_atomic_get_existing_crtc_state(state, plane_state->crtc);
crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc);
ret = drm_atomic_add_affected_connectors(state, plane_state->crtc);
if (ret)

View File

@@ -967,7 +967,7 @@ drm_vram_helper_mode_valid_internal(struct drm_device *dev,
max_fbpages = (vmm->vram_size / 2) >> PAGE_SHIFT;
fbsize = mode->hdisplay * mode->vdisplay * max_bpp;
fbsize = (u32)mode->hdisplay * mode->vdisplay * max_bpp;
fbpages = DIV_ROUND_UP(fbsize, PAGE_SIZE);
if (fbpages > max_fbpages)

View File

@@ -691,7 +691,7 @@ int mipi_dbi_dev_init(struct mipi_dbi_dev *dbidev,
const struct drm_simple_display_pipe_funcs *funcs,
const struct drm_display_mode *mode, unsigned int rotation)
{
size_t bufsize = mode->vdisplay * mode->hdisplay * sizeof(u16);
size_t bufsize = (u32)mode->vdisplay * mode->hdisplay * sizeof(u16);
dbidev->drm.mode_config.preferred_depth = 16;

View File

@@ -203,10 +203,10 @@ int drm_mode_config_helper_suspend(struct drm_device *dev)
if (dev->mode_config.poll_enabled)
drm_kms_helper_poll_disable(dev);
drm_client_dev_suspend(dev, false);
drm_client_dev_suspend(dev);
state = drm_atomic_helper_suspend(dev);
if (IS_ERR(state)) {
drm_client_dev_resume(dev, false);
drm_client_dev_resume(dev);
/*
* Don't enable polling if it was never initialized
@@ -252,7 +252,7 @@ int drm_mode_config_helper_resume(struct drm_device *dev)
DRM_ERROR("Failed to resume (%d)\n", ret);
dev->mode_config.suspend_state = NULL;
drm_client_dev_resume(dev, false);
drm_client_dev_resume(dev);
/*
* Don't enable polling if it is not initialized

View File

@@ -58,7 +58,7 @@ static void exynos_plane_mode_set(struct exynos_drm_plane_state *exynos_state)
struct drm_plane_state *state = &exynos_state->base;
struct drm_crtc *crtc = state->crtc;
struct drm_crtc_state *crtc_state =
drm_atomic_get_existing_crtc_state(state->state, crtc);
drm_atomic_get_new_crtc_state(state->state, crtc);
struct drm_display_mode *mode = &crtc_state->adjusted_mode;
int crtc_x, crtc_y;
unsigned int crtc_w, crtc_h;

View File

@@ -69,7 +69,7 @@ static size_t gud_xrgb8888_to_r124(u8 *dst, const struct drm_format_info *format
height = drm_rect_height(rect);
len = drm_format_info_min_pitch(format, 0, width) * height;
buf = kmalloc(width * height, GFP_KERNEL);
buf = kmalloc_array(height, width, GFP_KERNEL);
if (!buf)
return 0;

View File

@@ -978,7 +978,7 @@ void i915_driver_shutdown(struct drm_i915_private *i915)
intel_runtime_pm_disable(&i915->runtime_pm);
intel_power_domains_disable(display);
drm_client_dev_suspend(&i915->drm, false);
drm_client_dev_suspend(&i915->drm);
if (intel_display_device_present(display)) {
drm_kms_helper_poll_disable(&i915->drm);
intel_display_driver_disable_user_access(display);
@@ -1061,7 +1061,7 @@ static int i915_drm_suspend(struct drm_device *dev)
/* We do a lot of poking in a lot of registers, make sure they work
* properly. */
intel_power_domains_disable(display);
drm_client_dev_suspend(dev, false);
drm_client_dev_suspend(dev);
if (intel_display_device_present(display)) {
drm_kms_helper_poll_disable(dev);
intel_display_driver_disable_user_access(display);
@@ -1245,7 +1245,7 @@ static int i915_drm_resume(struct drm_device *dev)
intel_opregion_resume(display);
drm_client_dev_resume(dev, false);
drm_client_dev_resume(dev);
intel_power_domains_enable(display);

View File

@@ -15,12 +15,12 @@
#include "dc-pe.h"
#define PIXENGCFG_STATIC 0x8
#define POWERDOWN BIT(4)
#define SYNC_MODE BIT(8)
#define SINGLE 0
#define DIV_MASK GENMASK(23, 16)
#define DIV(x) FIELD_PREP(DIV_MASK, (x))
#define DIV_RESET 0x80
#define SYNC_MODE BIT(8)
#define SINGLE 0
#define POWERDOWN BIT(4)
#define PIXENGCFG_DYNAMIC 0xc
@@ -28,9 +28,9 @@
#define SYNC_TRIGGER BIT(0)
#define STATICCONTROL 0x8
#define PERFCOUNTMODE BIT(12)
#define KICK_MODE BIT(8)
#define EXTERNAL BIT(8)
#define PERFCOUNTMODE BIT(12)
#define CONTROL 0xc
#define GAMMAAPPLYENABLE BIT(0)

View File

@@ -56,9 +56,9 @@
#define FGINCTRL 0x5c
#define FGINCTRLPANIC 0x60
#define FGDM_MASK GENMASK(2, 0)
#define ENPRIMALPHA BIT(3)
#define ENSECALPHA BIT(4)
#define ENPRIMALPHA BIT(3)
#define FGDM_MASK GENMASK(2, 0)
#define FGCCR 0x64
#define CCGREEN(x) FIELD_PREP(GENMASK(19, 10), (x))

View File

@@ -18,11 +18,11 @@
#define BASEADDRESSAUTOUPDATE(x) FIELD_PREP(BASEADDRESSAUTOUPDATE_MASK, (x))
/* BURSTBUFFERMANAGEMENT */
#define LINEMODE_MASK BIT(31)
#define SETBURSTLENGTH_MASK GENMASK(12, 8)
#define SETBURSTLENGTH(x) FIELD_PREP(SETBURSTLENGTH_MASK, (x))
#define SETNUMBUFFERS_MASK GENMASK(7, 0)
#define SETNUMBUFFERS(x) FIELD_PREP(SETNUMBUFFERS_MASK, (x))
#define LINEMODE_MASK BIT(31)
/* SOURCEBUFFERATTRIBUTES */
#define BITSPERPIXEL_MASK GENMASK(21, 16)
@@ -31,20 +31,20 @@
#define STRIDE(x) FIELD_PREP(STRIDE_MASK, (x) - 1)
/* SOURCEBUFFERDIMENSION */
#define LINEWIDTH(x) FIELD_PREP(GENMASK(13, 0), (x))
#define LINECOUNT(x) FIELD_PREP(GENMASK(29, 16), (x))
#define LINEWIDTH(x) FIELD_PREP(GENMASK(13, 0), (x))
/* LAYEROFFSET */
#define LAYERXOFFSET(x) FIELD_PREP(GENMASK(14, 0), (x))
#define LAYERYOFFSET(x) FIELD_PREP(GENMASK(30, 16), (x))
#define LAYERXOFFSET(x) FIELD_PREP(GENMASK(14, 0), (x))
/* CLIPWINDOWOFFSET */
#define CLIPWINDOWXOFFSET(x) FIELD_PREP(GENMASK(14, 0), (x))
#define CLIPWINDOWYOFFSET(x) FIELD_PREP(GENMASK(30, 16), (x))
#define CLIPWINDOWXOFFSET(x) FIELD_PREP(GENMASK(14, 0), (x))
/* CLIPWINDOWDIMENSIONS */
#define CLIPWINDOWWIDTH(x) FIELD_PREP(GENMASK(13, 0), (x) - 1)
#define CLIPWINDOWHEIGHT(x) FIELD_PREP(GENMASK(29, 16), (x) - 1)
#define CLIPWINDOWWIDTH(x) FIELD_PREP(GENMASK(13, 0), (x) - 1)
enum dc_linemode {
/*

View File

@@ -33,13 +33,13 @@
#define A_SHIFT(x) FIELD_PREP_CONST(GENMASK(4, 0), (x))
/* LAYERPROPERTY */
#define SOURCEBUFFERENABLE BIT(31)
#define YUVCONVERSIONMODE_MASK GENMASK(18, 17)
#define YUVCONVERSIONMODE(x) FIELD_PREP(YUVCONVERSIONMODE_MASK, (x))
#define SOURCEBUFFERENABLE BIT(31)
/* FRAMEDIMENSIONS */
#define FRAMEWIDTH(x) FIELD_PREP(GENMASK(13, 0), (x))
#define FRAMEHEIGHT(x) FIELD_PREP(GENMASK(29, 16), (x))
#define FRAMEWIDTH(x) FIELD_PREP(GENMASK(13, 0), (x))
/* CONTROL */
#define INPUTSELECT_MASK GENMASK(4, 3)

View File

@@ -17,12 +17,12 @@
#include "dc-pe.h"
#define PIXENGCFG_DYNAMIC 0x8
#define PIXENGCFG_DYNAMIC_PRIM_SEL_MASK GENMASK(5, 0)
#define PIXENGCFG_DYNAMIC_PRIM_SEL(x) \
FIELD_PREP(PIXENGCFG_DYNAMIC_PRIM_SEL_MASK, (x))
#define PIXENGCFG_DYNAMIC_SEC_SEL_MASK GENMASK(13, 8)
#define PIXENGCFG_DYNAMIC_SEC_SEL(x) \
FIELD_PREP(PIXENGCFG_DYNAMIC_SEC_SEL_MASK, (x))
#define PIXENGCFG_DYNAMIC_PRIM_SEL_MASK GENMASK(5, 0)
#define PIXENGCFG_DYNAMIC_PRIM_SEL(x) \
FIELD_PREP(PIXENGCFG_DYNAMIC_PRIM_SEL_MASK, (x))
#define STATICCONTROL 0x8
#define SHDTOKSEL_MASK GENMASK(4, 3)
@@ -37,24 +37,24 @@
#define BLENDCONTROL 0x10
#define ALPHA_MASK GENMASK(23, 16)
#define ALPHA(x) FIELD_PREP(ALPHA_MASK, (x))
#define PRIM_C_BLD_FUNC_MASK GENMASK(2, 0)
#define PRIM_C_BLD_FUNC(x) \
FIELD_PREP(PRIM_C_BLD_FUNC_MASK, (x))
#define SEC_C_BLD_FUNC_MASK GENMASK(6, 4)
#define SEC_C_BLD_FUNC(x) \
FIELD_PREP(SEC_C_BLD_FUNC_MASK, (x))
#define PRIM_A_BLD_FUNC_MASK GENMASK(10, 8)
#define PRIM_A_BLD_FUNC(x) \
FIELD_PREP(PRIM_A_BLD_FUNC_MASK, (x))
#define SEC_A_BLD_FUNC_MASK GENMASK(14, 12)
#define SEC_A_BLD_FUNC(x) \
FIELD_PREP(SEC_A_BLD_FUNC_MASK, (x))
#define PRIM_A_BLD_FUNC_MASK GENMASK(10, 8)
#define PRIM_A_BLD_FUNC(x) \
FIELD_PREP(PRIM_A_BLD_FUNC_MASK, (x))
#define SEC_C_BLD_FUNC_MASK GENMASK(6, 4)
#define SEC_C_BLD_FUNC(x) \
FIELD_PREP(SEC_C_BLD_FUNC_MASK, (x))
#define PRIM_C_BLD_FUNC_MASK GENMASK(2, 0)
#define PRIM_C_BLD_FUNC(x) \
FIELD_PREP(PRIM_C_BLD_FUNC_MASK, (x))
#define POSITION 0x14
#define XPOS_MASK GENMASK(15, 0)
#define XPOS(x) FIELD_PREP(XPOS_MASK, (x))
#define YPOS_MASK GENMASK(31, 16)
#define YPOS(x) FIELD_PREP(YPOS_MASK, (x))
#define XPOS_MASK GENMASK(15, 0)
#define XPOS(x) FIELD_PREP(XPOS_MASK, (x))
enum dc_lb_blend_func {
DC_LAYERBLEND_BLEND_ZERO,

View File

@@ -106,7 +106,7 @@ dc_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state)
}
crtc_state =
drm_atomic_get_existing_crtc_state(state, plane_state->crtc);
drm_atomic_get_new_crtc_state(state, plane_state->crtc);
if (WARN_ON(!crtc_state))
return -EINVAL;

View File

@@ -159,8 +159,8 @@ static int dcss_plane_atomic_check(struct drm_plane *plane,
dma_obj = drm_fb_dma_get_gem_obj(fb, 0);
WARN_ON(!dma_obj);
crtc_state = drm_atomic_get_existing_crtc_state(state,
new_plane_state->crtc);
crtc_state = drm_atomic_get_new_crtc_state(state,
new_plane_state->crtc);
hdisplay = crtc_state->adjusted_mode.hdisplay;
vdisplay = crtc_state->adjusted_mode.vdisplay;

View File

@@ -386,8 +386,7 @@ static int ipu_plane_atomic_check(struct drm_plane *plane,
return -EINVAL;
crtc_state =
drm_atomic_get_existing_crtc_state(state,
new_state->crtc);
drm_atomic_get_new_crtc_state(state, new_state->crtc);
if (WARN_ON(!crtc_state))
return -EINVAL;

View File

@@ -247,8 +247,8 @@ static void ingenic_drm_crtc_atomic_enable(struct drm_crtc *crtc,
struct ingenic_drm_private_state *priv_state;
unsigned int next_id;
priv_state = ingenic_drm_get_priv_state(priv, state);
if (WARN_ON(IS_ERR(priv_state)))
priv_state = ingenic_drm_get_new_priv_state(priv, state);
if (WARN_ON(!priv_state))
return;
/* Set addresses of our DMA descriptor chains */
@@ -340,6 +340,7 @@ static int ingenic_drm_crtc_atomic_check(struct drm_crtc *crtc,
crtc);
struct ingenic_drm *priv = drm_crtc_get_priv(crtc);
struct drm_plane_state *f1_state, *f0_state, *ipu_state = NULL;
struct ingenic_drm_private_state *priv_state;
if (crtc_state->gamma_lut &&
drm_color_lut_size(crtc_state->gamma_lut) != ARRAY_SIZE(priv->dma_hwdescs->palette)) {
@@ -347,6 +348,11 @@ static int ingenic_drm_crtc_atomic_check(struct drm_crtc *crtc,
return -EINVAL;
}
/* We will need the state in atomic_enable, so let's make sure it's part of the state */
priv_state = ingenic_drm_get_priv_state(priv, state);
if (IS_ERR(priv_state))
return PTR_ERR(priv_state);
if (drm_atomic_crtc_needs_modeset(crtc_state) && priv->soc_info->has_osd) {
f1_state = drm_atomic_get_plane_state(crtc_state->state,
&priv->f1);
@@ -471,8 +477,7 @@ static int ingenic_drm_plane_atomic_check(struct drm_plane *plane,
if (priv->soc_info->plane_f0_not_working && plane == &priv->f0)
return -EINVAL;
crtc_state = drm_atomic_get_existing_crtc_state(state,
crtc);
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
if (WARN_ON(!crtc_state))
return -EINVAL;

View File

@@ -580,7 +580,7 @@ static int ingenic_ipu_plane_atomic_check(struct drm_plane *plane,
if (!crtc)
return 0;
crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
if (WARN_ON(!crtc_state))
return -EINVAL;
@@ -705,7 +705,7 @@ ingenic_ipu_plane_atomic_set_property(struct drm_plane *plane,
ipu->sharpness = val;
if (state->crtc) {
crtc_state = drm_atomic_get_existing_crtc_state(state->state, state->crtc);
crtc_state = drm_atomic_get_new_crtc_state(state->state, state->crtc);
if (WARN_ON(!crtc_state))
return -EINVAL;

View File

@@ -129,8 +129,7 @@ static int kmb_plane_atomic_check(struct drm_plane *plane,
}
can_position = (plane->type == DRM_PLANE_TYPE_OVERLAY);
crtc_state =
drm_atomic_get_existing_crtc_state(state,
new_plane_state->crtc);
drm_atomic_get_new_crtc_state(state, new_plane_state->crtc);
return drm_atomic_helper_check_plane_state(new_plane_state,
crtc_state,
DRM_PLANE_NO_SCALING,

View File

@@ -96,8 +96,8 @@ static int logicvc_plane_atomic_check(struct drm_plane *drm_plane,
if (!new_state->crtc)
return 0;
crtc_state = drm_atomic_get_existing_crtc_state(new_state->state,
new_state->crtc);
crtc_state = drm_atomic_get_new_crtc_state(new_state->state,
new_state->crtc);
if (WARN_ON(!crtc_state))
return -EINVAL;

View File

@@ -196,7 +196,7 @@ static int lsdc_cursor_plane_atomic_async_check(struct drm_plane *plane,
return -EINVAL;
}
crtc_state = drm_atomic_get_existing_crtc_state(state, new_state->crtc);
crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
if (!crtc_state->active)
return -EINVAL;

View File

@@ -122,7 +122,8 @@ static int mtk_plane_atomic_async_check(struct drm_plane *plane,
if (ret)
return ret;
crtc_state = drm_atomic_get_existing_crtc_state(state, new_plane_state->crtc);
crtc_state = drm_atomic_get_new_crtc_state(state,
new_plane_state->crtc);
return drm_atomic_helper_check_plane_state(plane->state, crtc_state,
DRM_PLANE_NO_SCALING,

View File

@@ -336,8 +336,7 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane,
if (!crtc)
return 0;
crtc_state = drm_atomic_get_existing_crtc_state(state,
crtc);
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
if (WARN_ON(!crtc_state))
return -EINVAL;
@@ -373,8 +372,8 @@ static int mdp5_plane_atomic_async_check(struct drm_plane *plane,
int min_scale, max_scale;
int ret;
crtc_state = drm_atomic_get_existing_crtc_state(state,
new_plane_state->crtc);
crtc_state = drm_atomic_get_new_crtc_state(state,
new_plane_state->crtc);
if (WARN_ON(!crtc_state))
return -EINVAL;

View File

@@ -765,7 +765,7 @@ nouveau_display_suspend(struct drm_device *dev, bool runtime)
{
struct nouveau_display *disp = nouveau_display(dev);
drm_client_dev_suspend(dev, false);
drm_client_dev_suspend(dev);
if (drm_drv_uses_atomic_modeset(dev)) {
if (!runtime) {
@@ -796,7 +796,7 @@ nouveau_display_resume(struct drm_device *dev, bool runtime)
}
}
drm_client_dev_resume(dev, false);
drm_client_dev_resume(dev);
}
int

View File

@@ -229,7 +229,7 @@ static int omap_plane_atomic_check(struct drm_plane *plane,
if (!crtc)
return 0;
crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
/* we should have a crtc state if the plane is attached to a crtc */
if (WARN_ON(!crtc_state))
return 0;

View File

@@ -1888,6 +1888,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, "B133UAN02.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, &delay_200_500_e50, "B116XAK01.6"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x203d, &delay_200_500_e50, "B140HTN02.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x205c, &delay_200_500_e50, "B116XAN02.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x208d, &delay_200_500_e50, "B140HTN02.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, &delay_200_500_e50, "B116XTN02.3"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, &delay_200_500_e50, "B116XAN06.1"),

View File

@@ -74,7 +74,7 @@ static int panfrost_devfreq_get_dev_status(struct device *dev,
spin_unlock_irqrestore(&pfdevfreq->lock, irqflags);
dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n",
dev_dbg(pfdev->base.dev, "busy %lu total %lu %lu %% freq %lu MHz\n",
status->busy_time, status->total_time,
status->busy_time / (status->total_time / 100),
status->current_frequency / 1000 / 1000);
@@ -119,7 +119,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
int ret;
struct dev_pm_opp *opp;
unsigned long cur_freq;
struct device *dev = &pfdev->pdev->dev;
struct device *dev = pfdev->base.dev;
struct devfreq *devfreq;
struct thermal_cooling_device *cooling;
struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;

View File

@@ -20,9 +20,9 @@
static int panfrost_reset_init(struct panfrost_device *pfdev)
{
pfdev->rstc = devm_reset_control_array_get_optional_exclusive(pfdev->dev);
pfdev->rstc = devm_reset_control_array_get_optional_exclusive(pfdev->base.dev);
if (IS_ERR(pfdev->rstc)) {
dev_err(pfdev->dev, "get reset failed %ld\n", PTR_ERR(pfdev->rstc));
dev_err(pfdev->base.dev, "get reset failed %ld\n", PTR_ERR(pfdev->rstc));
return PTR_ERR(pfdev->rstc);
}
@@ -39,22 +39,22 @@ static int panfrost_clk_init(struct panfrost_device *pfdev)
int err;
unsigned long rate;
pfdev->clock = devm_clk_get(pfdev->dev, NULL);
pfdev->clock = devm_clk_get(pfdev->base.dev, NULL);
if (IS_ERR(pfdev->clock)) {
dev_err(pfdev->dev, "get clock failed %ld\n", PTR_ERR(pfdev->clock));
dev_err(pfdev->base.dev, "get clock failed %ld\n", PTR_ERR(pfdev->clock));
return PTR_ERR(pfdev->clock);
}
rate = clk_get_rate(pfdev->clock);
dev_info(pfdev->dev, "clock rate = %lu\n", rate);
dev_info(pfdev->base.dev, "clock rate = %lu\n", rate);
err = clk_prepare_enable(pfdev->clock);
if (err)
return err;
pfdev->bus_clock = devm_clk_get_optional(pfdev->dev, "bus");
pfdev->bus_clock = devm_clk_get_optional(pfdev->base.dev, "bus");
if (IS_ERR(pfdev->bus_clock)) {
dev_err(pfdev->dev, "get bus_clock failed %ld\n",
dev_err(pfdev->base.dev, "get bus_clock failed %ld\n",
PTR_ERR(pfdev->bus_clock));
err = PTR_ERR(pfdev->bus_clock);
goto disable_clock;
@@ -62,7 +62,7 @@ static int panfrost_clk_init(struct panfrost_device *pfdev)
if (pfdev->bus_clock) {
rate = clk_get_rate(pfdev->bus_clock);
dev_info(pfdev->dev, "bus_clock rate = %lu\n", rate);
dev_info(pfdev->base.dev, "bus_clock rate = %lu\n", rate);
err = clk_prepare_enable(pfdev->bus_clock);
if (err)
@@ -87,7 +87,7 @@ static int panfrost_regulator_init(struct panfrost_device *pfdev)
{
int ret, i;
pfdev->regulators = devm_kcalloc(pfdev->dev, pfdev->comp->num_supplies,
pfdev->regulators = devm_kcalloc(pfdev->base.dev, pfdev->comp->num_supplies,
sizeof(*pfdev->regulators),
GFP_KERNEL);
if (!pfdev->regulators)
@@ -96,12 +96,12 @@ static int panfrost_regulator_init(struct panfrost_device *pfdev)
for (i = 0; i < pfdev->comp->num_supplies; i++)
pfdev->regulators[i].supply = pfdev->comp->supply_names[i];
ret = devm_regulator_bulk_get(pfdev->dev,
ret = devm_regulator_bulk_get(pfdev->base.dev,
pfdev->comp->num_supplies,
pfdev->regulators);
if (ret < 0) {
if (ret != -EPROBE_DEFER)
dev_err(pfdev->dev, "failed to get regulators: %d\n",
dev_err(pfdev->base.dev, "failed to get regulators: %d\n",
ret);
return ret;
}
@@ -109,7 +109,7 @@ static int panfrost_regulator_init(struct panfrost_device *pfdev)
ret = regulator_bulk_enable(pfdev->comp->num_supplies,
pfdev->regulators);
if (ret < 0) {
dev_err(pfdev->dev, "failed to enable regulators: %d\n", ret);
dev_err(pfdev->base.dev, "failed to enable regulators: %d\n", ret);
return ret;
}
@@ -144,7 +144,7 @@ static int panfrost_pm_domain_init(struct panfrost_device *pfdev)
int err;
int i, num_domains;
num_domains = of_count_phandle_with_args(pfdev->dev->of_node,
num_domains = of_count_phandle_with_args(pfdev->base.dev->of_node,
"power-domains",
"#power-domain-cells");
@@ -156,7 +156,7 @@ static int panfrost_pm_domain_init(struct panfrost_device *pfdev)
return 0;
if (num_domains != pfdev->comp->num_pm_domains) {
dev_err(pfdev->dev,
dev_err(pfdev->base.dev,
"Incorrect number of power domains: %d provided, %d needed\n",
num_domains, pfdev->comp->num_pm_domains);
return -EINVAL;
@@ -168,20 +168,21 @@ static int panfrost_pm_domain_init(struct panfrost_device *pfdev)
for (i = 0; i < num_domains; i++) {
pfdev->pm_domain_devs[i] =
dev_pm_domain_attach_by_name(pfdev->dev,
pfdev->comp->pm_domain_names[i]);
dev_pm_domain_attach_by_name(pfdev->base.dev,
pfdev->comp->pm_domain_names[i]);
if (IS_ERR_OR_NULL(pfdev->pm_domain_devs[i])) {
err = PTR_ERR(pfdev->pm_domain_devs[i]) ? : -ENODATA;
pfdev->pm_domain_devs[i] = NULL;
dev_err(pfdev->dev,
dev_err(pfdev->base.dev,
"failed to get pm-domain %s(%d): %d\n",
pfdev->comp->pm_domain_names[i], i, err);
goto err;
}
pfdev->pm_domain_links[i] = device_link_add(pfdev->dev,
pfdev->pm_domain_devs[i], DL_FLAG_PM_RUNTIME |
DL_FLAG_STATELESS | DL_FLAG_RPM_ACTIVE);
pfdev->pm_domain_links[i] =
device_link_add(pfdev->base.dev,
pfdev->pm_domain_devs[i], DL_FLAG_PM_RUNTIME |
DL_FLAG_STATELESS | DL_FLAG_RPM_ACTIVE);
if (!pfdev->pm_domain_links[i]) {
dev_err(pfdev->pm_domain_devs[i],
"adding device link failed!\n");
@@ -220,20 +221,20 @@ int panfrost_device_init(struct panfrost_device *pfdev)
err = panfrost_reset_init(pfdev);
if (err) {
dev_err(pfdev->dev, "reset init failed %d\n", err);
dev_err(pfdev->base.dev, "reset init failed %d\n", err);
goto out_pm_domain;
}
err = panfrost_clk_init(pfdev);
if (err) {
dev_err(pfdev->dev, "clk init failed %d\n", err);
dev_err(pfdev->base.dev, "clk init failed %d\n", err);
goto out_reset;
}
err = panfrost_devfreq_init(pfdev);
if (err) {
if (err != -EPROBE_DEFER)
dev_err(pfdev->dev, "devfreq init failed %d\n", err);
dev_err(pfdev->base.dev, "devfreq init failed %d\n", err);
goto out_clk;
}
@@ -244,7 +245,7 @@ int panfrost_device_init(struct panfrost_device *pfdev)
goto out_devfreq;
}
pfdev->iomem = devm_platform_ioremap_resource(pfdev->pdev, 0);
pfdev->iomem = devm_platform_ioremap_resource(to_platform_device(pfdev->base.dev), 0);
if (IS_ERR(pfdev->iomem)) {
err = PTR_ERR(pfdev->iomem);
goto out_regulator;
@@ -258,7 +259,7 @@ int panfrost_device_init(struct panfrost_device *pfdev)
if (err)
goto out_gpu;
err = panfrost_job_init(pfdev);
err = panfrost_jm_init(pfdev);
if (err)
goto out_mmu;
@@ -268,7 +269,7 @@ int panfrost_device_init(struct panfrost_device *pfdev)
return 0;
out_job:
panfrost_job_fini(pfdev);
panfrost_jm_fini(pfdev);
out_mmu:
panfrost_mmu_fini(pfdev);
out_gpu:
@@ -289,7 +290,7 @@ out_pm_domain:
void panfrost_device_fini(struct panfrost_device *pfdev)
{
panfrost_perfcnt_fini(pfdev);
panfrost_job_fini(pfdev);
panfrost_jm_fini(pfdev);
panfrost_mmu_fini(pfdev);
panfrost_gpu_fini(pfdev);
panfrost_devfreq_fini(pfdev);
@@ -399,13 +400,16 @@ bool panfrost_exception_needs_reset(const struct panfrost_device *pfdev,
return false;
}
void panfrost_device_reset(struct panfrost_device *pfdev)
void panfrost_device_reset(struct panfrost_device *pfdev, bool enable_job_int)
{
panfrost_gpu_soft_reset(pfdev);
panfrost_gpu_power_on(pfdev);
panfrost_mmu_reset(pfdev);
panfrost_job_enable_interrupts(pfdev);
panfrost_jm_reset_interrupts(pfdev);
if (enable_job_int)
panfrost_jm_enable_interrupts(pfdev);
}
static int panfrost_device_runtime_resume(struct device *dev)
@@ -429,7 +433,7 @@ static int panfrost_device_runtime_resume(struct device *dev)
}
}
panfrost_device_reset(pfdev);
panfrost_device_reset(pfdev, true);
panfrost_devfreq_resume(pfdev);
return 0;
@@ -447,11 +451,11 @@ static int panfrost_device_runtime_suspend(struct device *dev)
{
struct panfrost_device *pfdev = dev_get_drvdata(dev);
if (!panfrost_job_is_idle(pfdev))
if (!panfrost_jm_is_idle(pfdev))
return -EBUSY;
panfrost_devfreq_suspend(pfdev);
panfrost_job_suspend_irq(pfdev);
panfrost_jm_suspend_irq(pfdev);
panfrost_mmu_suspend_irq(pfdev);
panfrost_gpu_suspend_irq(pfdev);
panfrost_gpu_power_off(pfdev);

View File

@@ -26,6 +26,10 @@ struct panfrost_perfcnt;
#define MAX_PM_DOMAINS 5
#define ALL_JS_INT_MASK \
(GENMASK(16 + NUM_JOB_SLOTS - 1, 16) | \
GENMASK(NUM_JOB_SLOTS - 1, 0))
enum panfrost_drv_comp_bits {
PANFROST_COMP_BIT_GPU,
PANFROST_COMP_BIT_JOB,
@@ -124,9 +128,7 @@ struct panfrost_device_debugfs {
};
struct panfrost_device {
struct device *dev;
struct drm_device *ddev;
struct platform_device *pdev;
struct drm_device base;
int gpu_irq;
int mmu_irq;
@@ -145,7 +147,6 @@ struct panfrost_device {
DECLARE_BITMAP(is_suspended, PANFROST_COMP_BIT_MAX);
spinlock_t as_lock;
unsigned long as_in_use_mask;
unsigned long as_alloc_mask;
unsigned long as_faulty_mask;
struct list_head as_lru_list;
@@ -222,7 +223,7 @@ static inline bool panfrost_high_prio_allowed(struct drm_file *file)
static inline struct panfrost_device *to_panfrost_device(struct drm_device *ddev)
{
return ddev->dev_private;
return container_of(ddev, struct panfrost_device, base);
}
static inline int panfrost_model_cmp(struct panfrost_device *pfdev, s32 id)
@@ -248,7 +249,7 @@ int panfrost_unstable_ioctl_check(void);
int panfrost_device_init(struct panfrost_device *pfdev);
void panfrost_device_fini(struct panfrost_device *pfdev);
void panfrost_device_reset(struct panfrost_device *pfdev);
void panfrost_device_reset(struct panfrost_device *pfdev, bool enable_job_int);
extern const struct dev_pm_ops panfrost_pm_ops;

View File

@@ -36,7 +36,7 @@ static int panfrost_ioctl_query_timestamp(struct panfrost_device *pfdev,
{
int ret;
ret = pm_runtime_resume_and_get(pfdev->dev);
ret = pm_runtime_resume_and_get(pfdev->base.dev);
if (ret)
return ret;
@@ -44,14 +44,14 @@ static int panfrost_ioctl_query_timestamp(struct panfrost_device *pfdev,
*arg = panfrost_timestamp_read(pfdev);
panfrost_cycle_counter_put(pfdev);
pm_runtime_put(pfdev->dev);
pm_runtime_put(pfdev->base.dev);
return 0;
}
static int panfrost_ioctl_get_param(struct drm_device *ddev, void *data, struct drm_file *file)
{
struct drm_panfrost_get_param *param = data;
struct panfrost_device *pfdev = ddev->dev_private;
struct panfrost_device *pfdev = to_panfrost_device(ddev);
int ret;
if (param->pad != 0)
@@ -283,7 +283,7 @@ fail:
static int panfrost_ioctl_submit(struct drm_device *dev, void *data,
struct drm_file *file)
{
struct panfrost_device *pfdev = dev->dev_private;
struct panfrost_device *pfdev = to_panfrost_device(dev);
struct panfrost_file_priv *file_priv = file->driver_priv;
struct drm_panfrost_submit *args = data;
struct drm_syncobj *sync_out = NULL;
@@ -457,7 +457,7 @@ static int panfrost_ioctl_madvise(struct drm_device *dev, void *data,
{
struct panfrost_file_priv *priv = file_priv->driver_priv;
struct drm_panfrost_madvise *args = data;
struct panfrost_device *pfdev = dev->dev_private;
struct panfrost_device *pfdev = to_panfrost_device(dev);
struct drm_gem_object *gem_obj;
struct panfrost_gem_object *bo;
int ret = 0;
@@ -590,7 +590,7 @@ static int
panfrost_open(struct drm_device *dev, struct drm_file *file)
{
int ret;
struct panfrost_device *pfdev = dev->dev_private;
struct panfrost_device *pfdev = to_panfrost_device(dev);
struct panfrost_file_priv *panfrost_priv;
panfrost_priv = kzalloc(sizeof(*panfrost_priv), GFP_KERNEL);
@@ -606,7 +606,7 @@ panfrost_open(struct drm_device *dev, struct drm_file *file)
goto err_free;
}
ret = panfrost_job_open(file);
ret = panfrost_jm_open(file);
if (ret)
goto err_job;
@@ -625,7 +625,7 @@ panfrost_postclose(struct drm_device *dev, struct drm_file *file)
struct panfrost_file_priv *panfrost_priv = file->driver_priv;
panfrost_perfcnt_close(file);
panfrost_job_close(file);
panfrost_jm_close(file);
panfrost_mmu_ctx_put(panfrost_priv->mmu);
kfree(panfrost_priv);
@@ -668,30 +668,25 @@ static void panfrost_gpu_show_fdinfo(struct panfrost_device *pfdev,
* job spent on the GPU.
*/
static const char * const engine_names[] = {
"fragment", "vertex-tiler", "compute-only"
};
BUILD_BUG_ON(ARRAY_SIZE(engine_names) != NUM_JOB_SLOTS);
for (i = 0; i < NUM_JOB_SLOTS - 1; i++) {
if (pfdev->profile_mode) {
drm_printf(p, "drm-engine-%s:\t%llu ns\n",
engine_names[i], panfrost_priv->engine_usage.elapsed_ns[i]);
panfrost_engine_names[i],
panfrost_priv->engine_usage.elapsed_ns[i]);
drm_printf(p, "drm-cycles-%s:\t%llu\n",
engine_names[i], panfrost_priv->engine_usage.cycles[i]);
panfrost_engine_names[i],
panfrost_priv->engine_usage.cycles[i]);
}
drm_printf(p, "drm-maxfreq-%s:\t%lu Hz\n",
engine_names[i], pfdev->pfdevfreq.fast_rate);
panfrost_engine_names[i], pfdev->pfdevfreq.fast_rate);
drm_printf(p, "drm-curfreq-%s:\t%lu Hz\n",
engine_names[i], pfdev->pfdevfreq.current_frequency);
panfrost_engine_names[i], pfdev->pfdevfreq.current_frequency);
}
}
static void panfrost_show_fdinfo(struct drm_printer *p, struct drm_file *file)
{
struct drm_device *dev = file->minor->dev;
struct panfrost_device *pfdev = dev->dev_private;
struct panfrost_device *pfdev = to_panfrost_device(file->minor->dev);
panfrost_gpu_show_fdinfo(pfdev, file->driver_priv, p);
@@ -708,8 +703,7 @@ static const struct file_operations panfrost_drm_driver_fops = {
static int panthor_gems_show(struct seq_file *m, void *data)
{
struct drm_info_node *node = m->private;
struct drm_device *dev = node->minor->dev;
struct panfrost_device *pfdev = dev->dev_private;
struct panfrost_device *pfdev = to_panfrost_device(node->minor->dev);
panfrost_gem_debugfs_print_bos(pfdev, m);
@@ -758,7 +752,8 @@ static int show_file_jm_ctxs(struct panfrost_file_priv *pfile,
}
static struct drm_info_list panthor_debugfs_list[] = {
{"gems", panthor_gems_show, 0, NULL},
{"gems",
panthor_gems_show, 0, NULL},
};
static int panthor_gems_debugfs_init(struct drm_minor *minor)
@@ -865,15 +860,12 @@ static const struct drm_driver panfrost_drm_driver = {
static int panfrost_probe(struct platform_device *pdev)
{
struct panfrost_device *pfdev;
struct drm_device *ddev;
int err;
pfdev = devm_kzalloc(&pdev->dev, sizeof(*pfdev), GFP_KERNEL);
if (!pfdev)
return -ENOMEM;
pfdev->pdev = pdev;
pfdev->dev = &pdev->dev;
pfdev = devm_drm_dev_alloc(&pdev->dev, &panfrost_drm_driver,
struct panfrost_device, base);
if (IS_ERR(pfdev))
return PTR_ERR(pfdev);
platform_set_drvdata(pdev, pfdev);
@@ -883,14 +875,6 @@ static int panfrost_probe(struct platform_device *pdev)
pfdev->coherent = device_get_dma_attr(&pdev->dev) == DEV_DMA_COHERENT;
/* Allocate and initialize the DRM device. */
ddev = drm_dev_alloc(&panfrost_drm_driver, &pdev->dev);
if (IS_ERR(ddev))
return PTR_ERR(ddev);
ddev->dev_private = pfdev;
pfdev->ddev = ddev;
mutex_init(&pfdev->shrinker_lock);
INIT_LIST_HEAD(&pfdev->shrinker_list);
@@ -901,51 +885,47 @@ static int panfrost_probe(struct platform_device *pdev)
goto err_out0;
}
pm_runtime_set_active(pfdev->dev);
pm_runtime_mark_last_busy(pfdev->dev);
pm_runtime_enable(pfdev->dev);
pm_runtime_set_autosuspend_delay(pfdev->dev, 50); /* ~3 frames */
pm_runtime_use_autosuspend(pfdev->dev);
pm_runtime_set_active(pfdev->base.dev);
pm_runtime_mark_last_busy(pfdev->base.dev);
pm_runtime_enable(pfdev->base.dev);
pm_runtime_set_autosuspend_delay(pfdev->base.dev, 50); /* ~3 frames */
pm_runtime_use_autosuspend(pfdev->base.dev);
/*
* Register the DRM device with the core and the connectors with
* sysfs
*/
err = drm_dev_register(ddev, 0);
err = drm_dev_register(&pfdev->base, 0);
if (err < 0)
goto err_out1;
err = panfrost_gem_shrinker_init(ddev);
err = panfrost_gem_shrinker_init(&pfdev->base);
if (err)
goto err_out2;
return 0;
err_out2:
drm_dev_unregister(ddev);
drm_dev_unregister(&pfdev->base);
err_out1:
pm_runtime_disable(pfdev->dev);
pm_runtime_disable(pfdev->base.dev);
panfrost_device_fini(pfdev);
pm_runtime_set_suspended(pfdev->dev);
pm_runtime_set_suspended(pfdev->base.dev);
err_out0:
drm_dev_put(ddev);
return err;
}
static void panfrost_remove(struct platform_device *pdev)
{
struct panfrost_device *pfdev = platform_get_drvdata(pdev);
struct drm_device *ddev = pfdev->ddev;
drm_dev_unregister(ddev);
panfrost_gem_shrinker_cleanup(ddev);
drm_dev_unregister(&pfdev->base);
panfrost_gem_shrinker_cleanup(&pfdev->base);
pm_runtime_get_sync(pfdev->dev);
pm_runtime_disable(pfdev->dev);
pm_runtime_get_sync(pfdev->base.dev);
pm_runtime_disable(pfdev->base.dev);
panfrost_device_fini(pfdev);
pm_runtime_set_suspended(pfdev->dev);
drm_dev_put(ddev);
pm_runtime_set_suspended(pfdev->base.dev);
}
static ssize_t profiling_show(struct device *dev,

View File

@@ -163,7 +163,7 @@ void panfrost_core_dump(struct panfrost_job *job)
iter.start = __vmalloc(file_size, GFP_KERNEL | __GFP_NOWARN |
__GFP_NORETRY);
if (!iter.start) {
dev_warn(pfdev->dev, "failed to allocate devcoredump file\n");
dev_warn(pfdev->base.dev, "failed to allocate devcoredump file\n");
return;
}
@@ -204,14 +204,14 @@ void panfrost_core_dump(struct panfrost_job *job)
mapping = job->mappings[i];
if (!bo->base.sgt) {
dev_err(pfdev->dev, "Panfrost Dump: BO has no sgt, cannot dump\n");
dev_err(pfdev->base.dev, "Panfrost Dump: BO has no sgt, cannot dump\n");
iter.hdr->bomap.valid = 0;
goto dump_header;
}
ret = drm_gem_vmap(&bo->base.base, &map);
if (ret) {
dev_err(pfdev->dev, "Panfrost Dump: couldn't map Buffer Object\n");
dev_err(pfdev->base.dev, "Panfrost Dump: couldn't map Buffer Object\n");
iter.hdr->bomap.valid = 0;
goto dump_header;
}
@@ -237,5 +237,5 @@ dump_header: panfrost_core_dump_header(&iter, PANFROSTDUMP_BUF_BO, iter.data +
}
panfrost_core_dump_header(&iter, PANFROSTDUMP_BUF_TRAILER, iter.data);
dev_coredumpv(pfdev->dev, iter.start, iter.data - iter.start, GFP_KERNEL);
dev_coredumpv(pfdev->base.dev, iter.start, iter.data - iter.start, GFP_KERNEL);
}

View File

@@ -26,7 +26,7 @@ static void panfrost_gem_debugfs_bo_add(struct panfrost_device *pfdev,
static void panfrost_gem_debugfs_bo_rm(struct panfrost_gem_object *bo)
{
struct panfrost_device *pfdev = bo->base.base.dev->dev_private;
struct panfrost_device *pfdev = to_panfrost_device(bo->base.base.dev);
if (list_empty(&bo->debugfs.node))
return;
@@ -48,7 +48,7 @@ static void panfrost_gem_debugfs_bo_rm(struct panfrost_gem_object *bo) {}
static void panfrost_gem_free_object(struct drm_gem_object *obj)
{
struct panfrost_gem_object *bo = to_panfrost_bo(obj);
struct panfrost_device *pfdev = obj->dev->dev_private;
struct panfrost_device *pfdev = to_panfrost_device(obj->dev);
/*
* Make sure the BO is no longer inserted in the shrinker list before
@@ -76,7 +76,7 @@ static void panfrost_gem_free_object(struct drm_gem_object *obj)
for (i = 0; i < n_sgt; i++) {
if (bo->sgts[i].sgl) {
dma_unmap_sgtable(pfdev->dev, &bo->sgts[i],
dma_unmap_sgtable(pfdev->base.dev, &bo->sgts[i],
DMA_BIDIRECTIONAL, 0);
sg_free_table(&bo->sgts[i]);
}
@@ -284,7 +284,7 @@ static const struct drm_gem_object_funcs panfrost_gem_funcs = {
*/
struct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t size)
{
struct panfrost_device *pfdev = dev->dev_private;
struct panfrost_device *pfdev = to_panfrost_device(dev);
struct panfrost_gem_object *obj;
obj = kzalloc(sizeof(*obj), GFP_KERNEL);

View File

@@ -97,7 +97,7 @@ panfrost_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc)
*/
int panfrost_gem_shrinker_init(struct drm_device *dev)
{
struct panfrost_device *pfdev = dev->dev_private;
struct panfrost_device *pfdev = to_panfrost_device(dev);
pfdev->shrinker = shrinker_alloc(0, "drm-panfrost");
if (!pfdev->shrinker)
@@ -120,7 +120,7 @@ int panfrost_gem_shrinker_init(struct drm_device *dev)
*/
void panfrost_gem_shrinker_cleanup(struct drm_device *dev)
{
struct panfrost_device *pfdev = dev->dev_private;
struct panfrost_device *pfdev = to_panfrost_device(dev);
if (pfdev->shrinker)
shrinker_free(pfdev->shrinker);

View File

@@ -36,12 +36,12 @@ static irqreturn_t panfrost_gpu_irq_handler(int irq, void *data)
u64 address = (u64) gpu_read(pfdev, GPU_FAULT_ADDRESS_HI) << 32;
address |= gpu_read(pfdev, GPU_FAULT_ADDRESS_LO);
dev_warn(pfdev->dev, "GPU Fault 0x%08x (%s) at 0x%016llx\n",
dev_warn(pfdev->base.dev, "GPU Fault 0x%08x (%s) at 0x%016llx\n",
fault_status, panfrost_exception_name(fault_status & 0xFF),
address);
if (state & GPU_IRQ_MULTIPLE_FAULT)
dev_warn(pfdev->dev, "There were multiple GPU faults - some have not been reported\n");
dev_warn(pfdev->base.dev, "There were multiple GPU faults - some have not been reported\n");
gpu_write(pfdev, GPU_INT_MASK, 0);
}
@@ -72,13 +72,13 @@ int panfrost_gpu_soft_reset(struct panfrost_device *pfdev)
val, val & GPU_IRQ_RESET_COMPLETED, 10, 10000);
if (ret) {
dev_err(pfdev->dev, "gpu soft reset timed out, attempting hard reset\n");
dev_err(pfdev->base.dev, "gpu soft reset timed out, attempting hard reset\n");
gpu_write(pfdev, GPU_CMD, GPU_CMD_HARD_RESET);
ret = readl_relaxed_poll_timeout(pfdev->iomem + GPU_INT_RAWSTAT, val,
val & GPU_IRQ_RESET_COMPLETED, 100, 10000);
if (ret) {
dev_err(pfdev->dev, "gpu hard reset timed out\n");
dev_err(pfdev->base.dev, "gpu hard reset timed out\n");
return ret;
}
}
@@ -95,7 +95,7 @@ int panfrost_gpu_soft_reset(struct panfrost_device *pfdev)
* All in-flight jobs should have released their cycle
* counter references upon reset, but let us make sure
*/
if (drm_WARN_ON(pfdev->ddev, atomic_read(&pfdev->cycle_counter.use_count) != 0))
if (drm_WARN_ON(&pfdev->base, atomic_read(&pfdev->cycle_counter.use_count) != 0))
atomic_set(&pfdev->cycle_counter.use_count, 0);
return 0;
@@ -240,9 +240,10 @@ static const struct panfrost_model gpu_models[] = {
/* MediaTek MT8188 Mali-G57 MC3 */
GPU_MODEL(g57, 0x9093,
GPU_REV(g57, 0, 0)),
{0},
};
static void panfrost_gpu_init_features(struct panfrost_device *pfdev)
static int panfrost_gpu_init_features(struct panfrost_device *pfdev)
{
u32 gpu_id, num_js, major, minor, status, rev;
const char *name = "unknown";
@@ -327,16 +328,22 @@ static void panfrost_gpu_init_features(struct panfrost_device *pfdev)
break;
}
if (!model->name) {
dev_err(pfdev->base.dev, "GPU model not found: mali-%s id rev %#x %#x\n",
name, gpu_id, rev);
return -ENODEV;
}
bitmap_from_u64(pfdev->features.hw_features, hw_feat);
bitmap_from_u64(pfdev->features.hw_issues, hw_issues);
dev_info(pfdev->dev, "mali-%s id 0x%x major 0x%x minor 0x%x status 0x%x",
dev_info(pfdev->base.dev, "mali-%s id 0x%x major 0x%x minor 0x%x status 0x%x",
name, gpu_id, major, minor, status);
dev_info(pfdev->dev, "features: %64pb, issues: %64pb",
dev_info(pfdev->base.dev, "features: %64pb, issues: %64pb",
pfdev->features.hw_features,
pfdev->features.hw_issues);
dev_info(pfdev->dev, "Features: L2:0x%08x Shader:0x%08x Tiler:0x%08x Mem:0x%0x MMU:0x%08x AS:0x%x JS:0x%x",
dev_info(pfdev->base.dev, "Features: L2:0x%08x Shader:0x%08x Tiler:0x%08x Mem:0x%0x MMU:0x%08x AS:0x%x JS:0x%x",
pfdev->features.l2_features,
pfdev->features.core_features,
pfdev->features.tiler_features,
@@ -345,8 +352,10 @@ static void panfrost_gpu_init_features(struct panfrost_device *pfdev)
pfdev->features.as_present,
pfdev->features.js_present);
dev_info(pfdev->dev, "shader_present=0x%0llx l2_present=0x%0llx",
dev_info(pfdev->base.dev, "shader_present=0x%0llx l2_present=0x%0llx",
pfdev->features.shader_present, pfdev->features.l2_present);
return 0;
}
void panfrost_cycle_counter_get(struct panfrost_device *pfdev)
@@ -411,7 +420,7 @@ static u64 panfrost_get_core_mask(struct panfrost_device *pfdev)
*/
core_mask = ~(pfdev->features.l2_present - 1) &
(pfdev->features.l2_present - 2);
dev_info_once(pfdev->dev, "using only 1st core group (%lu cores from %lu)\n",
dev_info_once(pfdev->base.dev, "using only 1st core group (%lu cores from %lu)\n",
hweight64(core_mask),
hweight64(pfdev->features.shader_present));
@@ -432,7 +441,7 @@ void panfrost_gpu_power_on(struct panfrost_device *pfdev)
val, val == (pfdev->features.l2_present & core_mask),
10, 20000);
if (ret)
dev_err(pfdev->dev, "error powering up gpu L2");
dev_err(pfdev->base.dev, "error powering up gpu L2");
gpu_write(pfdev, SHADER_PWRON_LO,
pfdev->features.shader_present & core_mask);
@@ -440,13 +449,13 @@ void panfrost_gpu_power_on(struct panfrost_device *pfdev)
val, val == (pfdev->features.shader_present & core_mask),
10, 20000);
if (ret)
dev_err(pfdev->dev, "error powering up gpu shader");
dev_err(pfdev->base.dev, "error powering up gpu shader");
gpu_write(pfdev, TILER_PWRON_LO, pfdev->features.tiler_present);
ret = readl_relaxed_poll_timeout(pfdev->iomem + TILER_READY_LO,
val, val == pfdev->features.tiler_present, 10, 1000);
if (ret)
dev_err(pfdev->dev, "error powering up gpu tiler");
dev_err(pfdev->base.dev, "error powering up gpu tiler");
}
void panfrost_gpu_power_off(struct panfrost_device *pfdev)
@@ -458,19 +467,19 @@ void panfrost_gpu_power_off(struct panfrost_device *pfdev)
ret = readl_relaxed_poll_timeout(pfdev->iomem + SHADER_PWRTRANS_LO,
val, !val, 1, 2000);
if (ret)
dev_err(pfdev->dev, "shader power transition timeout");
dev_err(pfdev->base.dev, "shader power transition timeout");
gpu_write(pfdev, TILER_PWROFF_LO, pfdev->features.tiler_present);
ret = readl_relaxed_poll_timeout(pfdev->iomem + TILER_PWRTRANS_LO,
val, !val, 1, 2000);
if (ret)
dev_err(pfdev->dev, "tiler power transition timeout");
dev_err(pfdev->base.dev, "tiler power transition timeout");
gpu_write(pfdev, L2_PWROFF_LO, pfdev->features.l2_present);
ret = readl_poll_timeout(pfdev->iomem + L2_PWRTRANS_LO,
val, !val, 0, 2000);
if (ret)
dev_err(pfdev->dev, "l2 power transition timeout");
dev_err(pfdev->base.dev, "l2 power transition timeout");
}
void panfrost_gpu_suspend_irq(struct panfrost_device *pfdev)
@@ -489,23 +498,26 @@ int panfrost_gpu_init(struct panfrost_device *pfdev)
if (err)
return err;
panfrost_gpu_init_features(pfdev);
err = dma_set_mask_and_coherent(pfdev->dev,
DMA_BIT_MASK(FIELD_GET(0xff00, pfdev->features.mmu_features)));
err = panfrost_gpu_init_features(pfdev);
if (err)
return err;
dma_set_max_seg_size(pfdev->dev, UINT_MAX);
err = dma_set_mask_and_coherent(pfdev->base.dev,
DMA_BIT_MASK(FIELD_GET(0xff00,
pfdev->features.mmu_features)));
if (err)
return err;
pfdev->gpu_irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "gpu");
dma_set_max_seg_size(pfdev->base.dev, UINT_MAX);
pfdev->gpu_irq = platform_get_irq_byname(to_platform_device(pfdev->base.dev), "gpu");
if (pfdev->gpu_irq < 0)
return pfdev->gpu_irq;
err = devm_request_irq(pfdev->dev, pfdev->gpu_irq, panfrost_gpu_irq_handler,
err = devm_request_irq(pfdev->base.dev, pfdev->gpu_irq, panfrost_gpu_irq_handler,
IRQF_SHARED, KBUILD_MODNAME "-gpu", pfdev);
if (err) {
dev_err(pfdev->dev, "failed to request gpu irq");
dev_err(pfdev->base.dev, "failed to request gpu irq");
return err;
}
@@ -525,9 +537,9 @@ u32 panfrost_gpu_get_latest_flush_id(struct panfrost_device *pfdev)
if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION)) {
/* Flush reduction only makes sense when the GPU is kept powered on between jobs */
if (pm_runtime_get_if_in_use(pfdev->dev)) {
if (pm_runtime_get_if_in_use(pfdev->base.dev)) {
flush_id = gpu_read(pfdev, GPU_LATEST_FLUSH_ID);
pm_runtime_put(pfdev->dev);
pm_runtime_put(pfdev->base.dev);
return flush_id;
}
}

View File

@@ -28,6 +28,10 @@
#define job_write(dev, reg, data) writel(data, dev->iomem + (reg))
#define job_read(dev, reg) readl(dev->iomem + (reg))
const char * const panfrost_engine_names[] = {
"fragment", "vertex-tiler", "compute-only"
};
struct panfrost_queue_state {
struct drm_gpu_scheduler sched;
u64 fence_context;
@@ -95,7 +99,7 @@ static struct dma_fence *panfrost_fence_create(struct panfrost_device *pfdev, in
if (!fence)
return ERR_PTR(-ENOMEM);
fence->dev = pfdev->ddev;
fence->dev = &pfdev->base;
fence->queue = js_num;
fence->seqno = ++js->queue[js_num].emit_seqno;
dma_fence_init(&fence->base, &panfrost_fence_ops, &js->job_lock,
@@ -196,7 +200,7 @@ panfrost_enqueue_job(struct panfrost_device *pfdev, int slot,
return 1;
}
static void panfrost_job_hw_submit(struct panfrost_job *job, int js)
static int panfrost_job_hw_submit(struct panfrost_job *job, int js)
{
struct panfrost_device *pfdev = job->pfdev;
unsigned int subslot;
@@ -204,17 +208,22 @@ static void panfrost_job_hw_submit(struct panfrost_job *job, int js)
u64 jc_head = job->jc;
int ret;
panfrost_devfreq_record_busy(&pfdev->pfdevfreq);
ret = pm_runtime_get_sync(pfdev->dev);
ret = pm_runtime_get_sync(pfdev->base.dev);
if (ret < 0)
return;
goto err_hwsubmit;
if (WARN_ON(job_read(pfdev, JS_COMMAND_NEXT(js)))) {
return;
ret = -EINVAL;
goto err_hwsubmit;
}
cfg = panfrost_mmu_as_get(pfdev, job->mmu);
ret = panfrost_mmu_as_get(pfdev, job->mmu);
if (ret < 0)
goto err_hwsubmit;
cfg = ret;
panfrost_devfreq_record_busy(&pfdev->pfdevfreq);
job_write(pfdev, JS_HEAD_NEXT_LO(js), lower_32_bits(jc_head));
job_write(pfdev, JS_HEAD_NEXT_HI(js), upper_32_bits(jc_head));
@@ -257,11 +266,17 @@ static void panfrost_job_hw_submit(struct panfrost_job *job, int js)
}
job_write(pfdev, JS_COMMAND_NEXT(js), JS_COMMAND_START);
dev_dbg(pfdev->dev,
dev_dbg(pfdev->base.dev,
"JS: Submitting atom %p to js[%d][%d] with head=0x%llx AS %d",
job, js, subslot, jc_head, cfg & 0xf);
}
spin_unlock(&pfdev->js->job_lock);
return 0;
err_hwsubmit:
pm_runtime_put_autosuspend(pfdev->base.dev);
return ret;
}
static int panfrost_acquire_object_fences(struct drm_gem_object **bos,
@@ -384,6 +399,7 @@ static struct dma_fence *panfrost_job_run(struct drm_sched_job *sched_job)
struct panfrost_device *pfdev = job->pfdev;
int slot = panfrost_job_get_slot(job);
struct dma_fence *fence = NULL;
int ret;
if (job->ctx->destroyed)
return ERR_PTR(-ECANCELED);
@@ -405,27 +421,27 @@ static struct dma_fence *panfrost_job_run(struct drm_sched_job *sched_job)
dma_fence_put(job->done_fence);
job->done_fence = dma_fence_get(fence);
panfrost_job_hw_submit(job, slot);
ret = panfrost_job_hw_submit(job, slot);
if (ret) {
dma_fence_put(fence);
return ERR_PTR(ret);
}
return fence;
}
void panfrost_job_enable_interrupts(struct panfrost_device *pfdev)
void panfrost_jm_reset_interrupts(struct panfrost_device *pfdev)
{
int j;
u32 irq_mask = 0;
clear_bit(PANFROST_COMP_BIT_JOB, pfdev->is_suspended);
for (j = 0; j < NUM_JOB_SLOTS; j++) {
irq_mask |= MK_JS_MASK(j);
}
job_write(pfdev, JOB_INT_CLEAR, irq_mask);
job_write(pfdev, JOB_INT_MASK, irq_mask);
job_write(pfdev, JOB_INT_CLEAR, ALL_JS_INT_MASK);
}
void panfrost_job_suspend_irq(struct panfrost_device *pfdev)
void panfrost_jm_enable_interrupts(struct panfrost_device *pfdev)
{
clear_bit(PANFROST_COMP_BIT_JOB, pfdev->is_suspended);
job_write(pfdev, JOB_INT_MASK, ALL_JS_INT_MASK);
}
void panfrost_jm_suspend_irq(struct panfrost_device *pfdev)
{
set_bit(PANFROST_COMP_BIT_JOB, pfdev->is_suspended);
@@ -442,12 +458,12 @@ static void panfrost_job_handle_err(struct panfrost_device *pfdev,
bool signal_fence = true;
if (!panfrost_exception_is_fault(js_status)) {
dev_dbg(pfdev->dev, "js event, js=%d, status=%s, head=0x%x, tail=0x%x",
dev_dbg(pfdev->base.dev, "js event, js=%d, status=%s, head=0x%x, tail=0x%x",
js, exception_name,
job_read(pfdev, JS_HEAD_LO(js)),
job_read(pfdev, JS_TAIL_LO(js)));
} else {
dev_err(pfdev->dev, "js fault, js=%d, status=%s, head=0x%x, tail=0x%x",
dev_err(pfdev->base.dev, "js fault, js=%d, status=%s, head=0x%x, tail=0x%x",
js, exception_name,
job_read(pfdev, JS_HEAD_LO(js)),
job_read(pfdev, JS_TAIL_LO(js)));
@@ -479,7 +495,7 @@ static void panfrost_job_handle_err(struct panfrost_device *pfdev,
if (signal_fence)
dma_fence_signal_locked(job->done_fence);
pm_runtime_put_autosuspend(pfdev->dev);
pm_runtime_put_autosuspend(pfdev->base.dev);
if (panfrost_exception_needs_reset(pfdev, js_status)) {
atomic_set(&pfdev->reset.pending, 1);
@@ -487,8 +503,8 @@ static void panfrost_job_handle_err(struct panfrost_device *pfdev,
}
}
static void panfrost_job_handle_done(struct panfrost_device *pfdev,
struct panfrost_job *job)
static void panfrost_jm_handle_done(struct panfrost_device *pfdev,
struct panfrost_job *job)
{
/* Set ->jc to 0 to avoid re-submitting an already finished job (can
* happen when we receive the DONE interrupt while doing a GPU reset).
@@ -498,10 +514,10 @@ static void panfrost_job_handle_done(struct panfrost_device *pfdev,
panfrost_devfreq_record_idle(&pfdev->pfdevfreq);
dma_fence_signal_locked(job->done_fence);
pm_runtime_put_autosuspend(pfdev->dev);
pm_runtime_put_autosuspend(pfdev->base.dev);
}
static void panfrost_job_handle_irq(struct panfrost_device *pfdev, u32 status)
static void panfrost_jm_handle_irq(struct panfrost_device *pfdev, u32 status)
{
struct panfrost_job *done[NUM_JOB_SLOTS][2] = {};
struct panfrost_job *failed[NUM_JOB_SLOTS] = {};
@@ -576,7 +592,7 @@ static void panfrost_job_handle_irq(struct panfrost_device *pfdev, u32 status)
}
for (i = 0; i < ARRAY_SIZE(done[0]) && done[j][i]; i++)
panfrost_job_handle_done(pfdev, done[j][i]);
panfrost_jm_handle_done(pfdev, done[j][i]);
}
/* And finally we requeue jobs that were waiting in the second slot
@@ -594,7 +610,7 @@ static void panfrost_job_handle_irq(struct panfrost_device *pfdev, u32 status)
struct panfrost_job *canceled = panfrost_dequeue_job(pfdev, j);
dma_fence_set_error(canceled->done_fence, -ECANCELED);
panfrost_job_handle_done(pfdev, canceled);
panfrost_jm_handle_done(pfdev, canceled);
} else if (!atomic_read(&pfdev->reset.pending)) {
/* Requeue the job we removed if no reset is pending */
job_write(pfdev, JS_COMMAND_NEXT(j), JS_COMMAND_START);
@@ -602,15 +618,15 @@ static void panfrost_job_handle_irq(struct panfrost_device *pfdev, u32 status)
}
}
static void panfrost_job_handle_irqs(struct panfrost_device *pfdev)
static void panfrost_jm_handle_irqs(struct panfrost_device *pfdev)
{
u32 status = job_read(pfdev, JOB_INT_RAWSTAT);
while (status) {
pm_runtime_mark_last_busy(pfdev->dev);
pm_runtime_mark_last_busy(pfdev->base.dev);
spin_lock(&pfdev->js->job_lock);
panfrost_job_handle_irq(pfdev, status);
panfrost_jm_handle_irq(pfdev, status);
spin_unlock(&pfdev->js->job_lock);
status = job_read(pfdev, JOB_INT_RAWSTAT);
}
@@ -688,10 +704,10 @@ panfrost_reset(struct panfrost_device *pfdev,
10, 10000);
if (ret)
dev_err(pfdev->dev, "Soft-stop failed\n");
dev_err(pfdev->base.dev, "Soft-stop failed\n");
/* Handle the remaining interrupts before we reset. */
panfrost_job_handle_irqs(pfdev);
panfrost_jm_handle_irqs(pfdev);
/* Remaining interrupts have been handled, but we might still have
* stuck jobs. Let's make sure the PM counters stay balanced by
@@ -706,7 +722,7 @@ panfrost_reset(struct panfrost_device *pfdev,
if (pfdev->jobs[i][j]->requirements & PANFROST_JD_REQ_CYCLE_COUNT ||
pfdev->jobs[i][j]->is_profiled)
panfrost_cycle_counter_put(pfdev->jobs[i][j]->pfdev);
pm_runtime_put_noidle(pfdev->dev);
pm_runtime_put_noidle(pfdev->base.dev);
panfrost_devfreq_record_idle(&pfdev->pfdevfreq);
}
}
@@ -714,12 +730,7 @@ panfrost_reset(struct panfrost_device *pfdev,
spin_unlock(&pfdev->js->job_lock);
/* Proceed with reset now. */
panfrost_device_reset(pfdev);
/* panfrost_device_reset() unmasks job interrupts, but we want to
* keep them masked a bit longer.
*/
job_write(pfdev, JOB_INT_MASK, 0);
panfrost_device_reset(pfdev, false);
/* GPU has been reset, we can clear the reset pending bit. */
atomic_set(&pfdev->reset.pending, 0);
@@ -741,9 +752,7 @@ panfrost_reset(struct panfrost_device *pfdev,
drm_sched_start(&pfdev->js->queue[i].sched, 0);
/* Re-enable job interrupts now that everything has been restarted. */
job_write(pfdev, JOB_INT_MASK,
GENMASK(16 + NUM_JOB_SLOTS - 1, 16) |
GENMASK(NUM_JOB_SLOTS - 1, 0));
panfrost_jm_enable_interrupts(pfdev);
dma_fence_end_signalling(cookie);
}
@@ -774,11 +783,11 @@ static enum drm_gpu_sched_stat panfrost_job_timedout(struct drm_sched_job
synchronize_irq(pfdev->js->irq);
if (dma_fence_is_signaled(job->done_fence)) {
dev_warn(pfdev->dev, "unexpectedly high interrupt latency\n");
dev_warn(pfdev->base.dev, "unexpectedly high interrupt latency\n");
return DRM_GPU_SCHED_STAT_NO_HANG;
}
dev_err(pfdev->dev, "gpu sched timeout, js=%d, config=0x%x, status=0x%x, head=0x%x, tail=0x%x, sched_job=%p",
dev_err(pfdev->base.dev, "gpu sched timeout, js=%d, config=0x%x, status=0x%x, head=0x%x, tail=0x%x, sched_job=%p",
js,
job_read(pfdev, JS_CONFIG(js)),
job_read(pfdev, JS_STATUS(js)),
@@ -808,22 +817,20 @@ static const struct drm_sched_backend_ops panfrost_sched_ops = {
.free_job = panfrost_job_free
};
static irqreturn_t panfrost_job_irq_handler_thread(int irq, void *data)
static irqreturn_t panfrost_jm_irq_handler_thread(int irq, void *data)
{
struct panfrost_device *pfdev = data;
panfrost_job_handle_irqs(pfdev);
panfrost_jm_handle_irqs(pfdev);
/* Enable interrupts only if we're not about to get suspended */
if (!test_bit(PANFROST_COMP_BIT_JOB, pfdev->is_suspended))
job_write(pfdev, JOB_INT_MASK,
GENMASK(16 + NUM_JOB_SLOTS - 1, 16) |
GENMASK(NUM_JOB_SLOTS - 1, 0));
job_write(pfdev, JOB_INT_MASK, ALL_JS_INT_MASK);
return IRQ_HANDLED;
}
static irqreturn_t panfrost_job_irq_handler(int irq, void *data)
static irqreturn_t panfrost_jm_irq_handler(int irq, void *data)
{
struct panfrost_device *pfdev = data;
u32 status;
@@ -839,19 +846,20 @@ static irqreturn_t panfrost_job_irq_handler(int irq, void *data)
return IRQ_WAKE_THREAD;
}
int panfrost_job_init(struct panfrost_device *pfdev)
int panfrost_jm_init(struct panfrost_device *pfdev)
{
struct drm_sched_init_args args = {
.ops = &panfrost_sched_ops,
.num_rqs = DRM_SCHED_PRIORITY_COUNT,
.credit_limit = 2,
.timeout = msecs_to_jiffies(JOB_TIMEOUT_MS),
.name = "pan_js",
.dev = pfdev->dev,
.dev = pfdev->base.dev,
};
struct panfrost_job_slot *js;
int ret, j;
BUILD_BUG_ON(ARRAY_SIZE(panfrost_engine_names) != NUM_JOB_SLOTS);
/* All GPUs have two entries per queue, but without jobchain
* disambiguation stopping the right job in the close path is tricky,
* so let's just advertise one entry in that case.
@@ -859,24 +867,25 @@ int panfrost_job_init(struct panfrost_device *pfdev)
if (!panfrost_has_hw_feature(pfdev, HW_FEATURE_JOBCHAIN_DISAMBIGUATION))
args.credit_limit = 1;
pfdev->js = js = devm_kzalloc(pfdev->dev, sizeof(*js), GFP_KERNEL);
js = devm_kzalloc(pfdev->base.dev, sizeof(*js), GFP_KERNEL);
if (!js)
return -ENOMEM;
pfdev->js = js;
INIT_WORK(&pfdev->reset.work, panfrost_reset_work);
spin_lock_init(&js->job_lock);
js->irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "job");
js->irq = platform_get_irq_byname(to_platform_device(pfdev->base.dev), "job");
if (js->irq < 0)
return js->irq;
ret = devm_request_threaded_irq(pfdev->dev, js->irq,
panfrost_job_irq_handler,
panfrost_job_irq_handler_thread,
ret = devm_request_threaded_irq(pfdev->base.dev, js->irq,
panfrost_jm_irq_handler,
panfrost_jm_irq_handler_thread,
IRQF_SHARED, KBUILD_MODNAME "-job",
pfdev);
if (ret) {
dev_err(pfdev->dev, "failed to request job irq");
dev_err(pfdev->base.dev, "failed to request job irq");
return ret;
}
@@ -887,15 +896,17 @@ int panfrost_job_init(struct panfrost_device *pfdev)
for (j = 0; j < NUM_JOB_SLOTS; j++) {
js->queue[j].fence_context = dma_fence_context_alloc(1);
args.name = panfrost_engine_names[j];
ret = drm_sched_init(&js->queue[j].sched, &args);
if (ret) {
dev_err(pfdev->dev, "Failed to create scheduler: %d.", ret);
dev_err(pfdev->base.dev, "Failed to create scheduler: %d.", ret);
goto err_sched;
}
}
panfrost_job_enable_interrupts(pfdev);
panfrost_jm_reset_interrupts(pfdev);
panfrost_jm_enable_interrupts(pfdev);
return 0;
@@ -907,7 +918,7 @@ err_sched:
return ret;
}
void panfrost_job_fini(struct panfrost_device *pfdev)
void panfrost_jm_fini(struct panfrost_device *pfdev)
{
struct panfrost_job_slot *js = pfdev->js;
int j;
@@ -922,7 +933,7 @@ void panfrost_job_fini(struct panfrost_device *pfdev)
destroy_workqueue(pfdev->reset.wq);
}
int panfrost_job_open(struct drm_file *file)
int panfrost_jm_open(struct drm_file *file)
{
struct panfrost_file_priv *panfrost_priv = file->driver_priv;
int ret;
@@ -944,7 +955,7 @@ int panfrost_job_open(struct drm_file *file)
return 0;
}
void panfrost_job_close(struct drm_file *file)
void panfrost_jm_close(struct drm_file *file)
{
struct panfrost_file_priv *panfrost_priv = file->driver_priv;
struct panfrost_jm_ctx *jm_ctx;
@@ -956,7 +967,7 @@ void panfrost_job_close(struct drm_file *file)
xa_destroy(&panfrost_priv->jm_ctxs);
}
int panfrost_job_is_idle(struct panfrost_device *pfdev)
int panfrost_jm_is_idle(struct panfrost_device *pfdev)
{
struct panfrost_job_slot *js = pfdev->js;
int i;

View File

@@ -53,6 +53,8 @@ struct panfrost_jm_ctx {
struct drm_sched_entity slot_entity[NUM_JOB_SLOTS];
};
extern const char * const panfrost_engine_names[];
int panfrost_jm_ctx_create(struct drm_file *file,
struct drm_panfrost_jm_ctx_create *args);
int panfrost_jm_ctx_destroy(struct drm_file *file, u32 handle);
@@ -60,15 +62,16 @@ void panfrost_jm_ctx_put(struct panfrost_jm_ctx *jm_ctx);
struct panfrost_jm_ctx *panfrost_jm_ctx_get(struct panfrost_jm_ctx *jm_ctx);
struct panfrost_jm_ctx *panfrost_jm_ctx_from_handle(struct drm_file *file, u32 handle);
int panfrost_job_init(struct panfrost_device *pfdev);
void panfrost_job_fini(struct panfrost_device *pfdev);
int panfrost_job_open(struct drm_file *file);
void panfrost_job_close(struct drm_file *file);
int panfrost_jm_init(struct panfrost_device *pfdev);
void panfrost_jm_fini(struct panfrost_device *pfdev);
int panfrost_jm_open(struct drm_file *file);
void panfrost_jm_close(struct drm_file *file);
void panfrost_jm_reset_interrupts(struct panfrost_device *pfdev);
void panfrost_jm_enable_interrupts(struct panfrost_device *pfdev);
void panfrost_jm_suspend_irq(struct panfrost_device *pfdev);
int panfrost_jm_is_idle(struct panfrost_device *pfdev);
int panfrost_job_get_slot(struct panfrost_job *job);
int panfrost_job_push(struct panfrost_job *job);
void panfrost_job_put(struct panfrost_job *job);
void panfrost_job_enable_interrupts(struct panfrost_device *pfdev);
void panfrost_job_suspend_irq(struct panfrost_device *pfdev);
int panfrost_job_is_idle(struct panfrost_device *pfdev);
#endif

View File

@@ -81,7 +81,7 @@ static int wait_ready(struct panfrost_device *pfdev, u32 as_nr)
if (ret) {
/* The GPU hung, let's trigger a reset */
panfrost_device_schedule_reset(pfdev);
dev_err(pfdev->dev, "AS_ACTIVE bit stuck\n");
dev_err(pfdev->base.dev, "AS_ACTIVE bit stuck\n");
}
return ret;
@@ -222,7 +222,7 @@ static int mmu_cfg_init_aarch64_4k(struct panfrost_mmu *mmu)
struct io_pgtable_cfg *pgtbl_cfg = &mmu->pgtbl_cfg;
struct panfrost_device *pfdev = mmu->pfdev;
if (drm_WARN_ON(pfdev->ddev, pgtbl_cfg->arm_lpae_s1_cfg.ttbr &
if (drm_WARN_ON(&pfdev->base, pgtbl_cfg->arm_lpae_s1_cfg.ttbr &
~AS_TRANSTAB_AARCH64_4K_ADDR_MASK))
return -EINVAL;
@@ -253,12 +253,12 @@ static int panfrost_mmu_cfg_init(struct panfrost_mmu *mmu,
return mmu_cfg_init_mali_lpae(mmu);
default:
/* This should never happen */
drm_WARN(pfdev->ddev, 1, "Invalid pgtable format");
drm_WARN(&pfdev->base, 1, "Invalid pgtable format");
return -EINVAL;
}
}
u32 panfrost_mmu_as_get(struct panfrost_device *pfdev, struct panfrost_mmu *mmu)
int panfrost_mmu_as_get(struct panfrost_device *pfdev, struct panfrost_mmu *mmu)
{
int as;
@@ -300,7 +300,10 @@ u32 panfrost_mmu_as_get(struct panfrost_device *pfdev, struct panfrost_mmu *mmu)
if (!atomic_read(&lru_mmu->as_count))
break;
}
WARN_ON(&lru_mmu->list == &pfdev->as_lru_list);
if (WARN_ON(&lru_mmu->list == &pfdev->as_lru_list)) {
as = -EBUSY;
goto out;
}
list_del_init(&lru_mmu->list);
as = lru_mmu->as;
@@ -315,7 +318,9 @@ u32 panfrost_mmu_as_get(struct panfrost_device *pfdev, struct panfrost_mmu *mmu)
atomic_set(&mmu->as_count, 1);
list_add(&mmu->list, &pfdev->as_lru_list);
dev_dbg(pfdev->dev, "Assigned AS%d to mmu %p, alloc_mask=%lx", as, mmu, pfdev->as_alloc_mask);
dev_dbg(pfdev->base.dev,
"Assigned AS%d to mmu %p, alloc_mask=%lx",
as, mmu, pfdev->as_alloc_mask);
panfrost_mmu_enable(pfdev, mmu);
@@ -381,13 +386,30 @@ static void panfrost_mmu_flush_range(struct panfrost_device *pfdev,
if (mmu->as < 0)
return;
pm_runtime_get_noresume(pfdev->dev);
pm_runtime_get_noresume(pfdev->base.dev);
/* Flush the PTs only if we're already awake */
if (pm_runtime_active(pfdev->dev))
if (pm_runtime_active(pfdev->base.dev))
mmu_hw_do_operation(pfdev, mmu, iova, size, AS_COMMAND_FLUSH_PT);
pm_runtime_put_autosuspend(pfdev->dev);
pm_runtime_put_autosuspend(pfdev->base.dev);
}
static void mmu_unmap_range(struct panfrost_mmu *mmu, u64 iova, size_t len)
{
struct io_pgtable_ops *ops = mmu->pgtbl_ops;
size_t pgsize, unmapped_len = 0;
size_t unmapped_page, pgcount;
while (unmapped_len < len) {
pgsize = get_pgsize(iova, len - unmapped_len, &pgcount);
unmapped_page = ops->unmap_pages(ops, iova, pgsize, pgcount, NULL);
WARN_ON(unmapped_page != pgsize * pgcount);
iova += pgsize * pgcount;
unmapped_len += pgsize * pgcount;
}
}
static int mmu_map_sg(struct panfrost_device *pfdev, struct panfrost_mmu *mmu,
@@ -396,22 +418,30 @@ static int mmu_map_sg(struct panfrost_device *pfdev, struct panfrost_mmu *mmu,
unsigned int count;
struct scatterlist *sgl;
struct io_pgtable_ops *ops = mmu->pgtbl_ops;
size_t total_mapped = 0;
u64 start_iova = iova;
int ret;
for_each_sgtable_dma_sg(sgt, sgl, count) {
unsigned long paddr = sg_dma_address(sgl);
size_t len = sg_dma_len(sgl);
dev_dbg(pfdev->dev, "map: as=%d, iova=%llx, paddr=%lx, len=%zx", mmu->as, iova, paddr, len);
dev_dbg(pfdev->base.dev,
"map: as=%d, iova=%llx, paddr=%lx, len=%zx",
mmu->as, iova, paddr, len);
while (len) {
size_t pgcount, mapped = 0;
size_t pgsize = get_pgsize(iova | paddr, len, &pgcount);
ops->map_pages(ops, iova, paddr, pgsize, pgcount, prot,
ret = ops->map_pages(ops, iova, paddr, pgsize, pgcount, prot,
GFP_KERNEL, &mapped);
if (ret)
goto err_unmap_pages;
/* Don't get stuck if things have gone wrong */
mapped = max(mapped, pgsize);
total_mapped += mapped;
iova += mapped;
paddr += mapped;
len -= mapped;
@@ -421,6 +451,10 @@ static int mmu_map_sg(struct panfrost_device *pfdev, struct panfrost_mmu *mmu,
panfrost_mmu_flush_range(pfdev, mmu, start_iova, iova - start_iova);
return 0;
err_unmap_pages:
mmu_unmap_range(mmu, start_iova, total_mapped);
return ret;
}
int panfrost_mmu_map(struct panfrost_gem_mapping *mapping)
@@ -431,6 +465,7 @@ int panfrost_mmu_map(struct panfrost_gem_mapping *mapping)
struct panfrost_device *pfdev = to_panfrost_device(obj->dev);
struct sg_table *sgt;
int prot = IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE;
int ret;
if (WARN_ON(mapping->active))
return 0;
@@ -442,11 +477,18 @@ int panfrost_mmu_map(struct panfrost_gem_mapping *mapping)
if (WARN_ON(IS_ERR(sgt)))
return PTR_ERR(sgt);
mmu_map_sg(pfdev, mapping->mmu, mapping->mmnode.start << PAGE_SHIFT,
prot, sgt);
ret = mmu_map_sg(pfdev, mapping->mmu, mapping->mmnode.start << PAGE_SHIFT,
prot, sgt);
if (ret)
goto err_put_pages;
mapping->active = true;
return 0;
err_put_pages:
drm_gem_shmem_put_pages_locked(shmem);
return ret;
}
void panfrost_mmu_unmap(struct panfrost_gem_mapping *mapping)
@@ -462,7 +504,7 @@ void panfrost_mmu_unmap(struct panfrost_gem_mapping *mapping)
if (WARN_ON(!mapping->active))
return;
dev_dbg(pfdev->dev, "unmap: as=%d, iova=%llx, len=%zx",
dev_dbg(pfdev->base.dev, "unmap: as=%d, iova=%llx, len=%zx",
mapping->mmu->as, iova, len);
while (unmapped_len < len) {
@@ -559,7 +601,7 @@ static int panfrost_mmu_map_fault_addr(struct panfrost_device *pfdev, int as,
bo = bomapping->obj;
if (!bo->is_heap) {
dev_WARN(pfdev->dev, "matching BO is not heap type (GPU VA = %llx)",
dev_WARN(pfdev->base.dev, "matching BO is not heap type (GPU VA = %llx)",
bomapping->mmnode.start << PAGE_SHIFT);
ret = -EINVAL;
goto err_bo;
@@ -595,10 +637,12 @@ static int panfrost_mmu_map_fault_addr(struct panfrost_device *pfdev, int as,
refcount_set(&bo->base.pages_use_count, 1);
} else {
pages = bo->base.pages;
if (pages[page_offset]) {
/* Pages are already mapped, bail out. */
goto out;
}
}
sgt = &bo->sgts[page_offset / (SZ_2M / PAGE_SIZE)];
if (sgt->sgl) {
/* Pages are already mapped, bail out. */
goto out;
}
mapping = bo->base.base.filp->f_mapping;
@@ -620,23 +664,24 @@ static int panfrost_mmu_map_fault_addr(struct panfrost_device *pfdev, int as,
}
}
sgt = &bo->sgts[page_offset / (SZ_2M / PAGE_SIZE)];
ret = sg_alloc_table_from_pages(sgt, pages + page_offset,
NUM_FAULT_PAGES, 0, SZ_2M, GFP_KERNEL);
if (ret)
goto err_unlock;
ret = dma_map_sgtable(pfdev->dev, sgt, DMA_BIDIRECTIONAL, 0);
ret = dma_map_sgtable(pfdev->base.dev, sgt, DMA_BIDIRECTIONAL, 0);
if (ret)
goto err_map;
mmu_map_sg(pfdev, bomapping->mmu, addr,
IOMMU_WRITE | IOMMU_READ | IOMMU_CACHE | IOMMU_NOEXEC, sgt);
ret = mmu_map_sg(pfdev, bomapping->mmu, addr,
IOMMU_WRITE | IOMMU_READ | IOMMU_CACHE | IOMMU_NOEXEC, sgt);
if (ret)
goto err_mmu_map_sg;
bomapping->active = true;
bo->heap_rss_size += SZ_2M;
dev_dbg(pfdev->dev, "mapped page fault @ AS%d %llx", as, addr);
dev_dbg(pfdev->base.dev, "mapped page fault @ AS%d %llx", as, addr);
out:
dma_resv_unlock(obj->resv);
@@ -645,6 +690,8 @@ out:
return 0;
err_mmu_map_sg:
dma_unmap_sgtable(pfdev->base.dev, sgt, DMA_BIDIRECTIONAL, 0);
err_map:
sg_free_table(sgt);
err_unlock:
@@ -662,13 +709,12 @@ static void panfrost_mmu_release_ctx(struct kref *kref)
spin_lock(&pfdev->as_lock);
if (mmu->as >= 0) {
pm_runtime_get_noresume(pfdev->dev);
if (pm_runtime_active(pfdev->dev))
pm_runtime_get_noresume(pfdev->base.dev);
if (pm_runtime_active(pfdev->base.dev))
panfrost_mmu_disable(pfdev, mmu->as);
pm_runtime_put_autosuspend(pfdev->dev);
pm_runtime_put_autosuspend(pfdev->base.dev);
clear_bit(mmu->as, &pfdev->as_alloc_mask);
clear_bit(mmu->as, &pfdev->as_in_use_mask);
list_del(&mmu->list);
}
spin_unlock(&pfdev->as_lock);
@@ -726,7 +772,7 @@ struct panfrost_mmu *panfrost_mmu_ctx_create(struct panfrost_device *pfdev)
if (pfdev->comp->gpu_quirks & BIT(GPU_QUIRK_FORCE_AARCH64_PGTABLE)) {
if (!panfrost_has_hw_feature(pfdev, HW_FEATURE_AARCH64_MMU)) {
dev_err_once(pfdev->dev,
dev_err_once(pfdev->base.dev,
"AARCH64_4K page table not supported\n");
return ERR_PTR(-EINVAL);
}
@@ -755,7 +801,7 @@ struct panfrost_mmu *panfrost_mmu_ctx_create(struct panfrost_device *pfdev)
.oas = pa_bits,
.coherent_walk = pfdev->coherent,
.tlb = &mmu_tlb_ops,
.iommu_dev = pfdev->dev,
.iommu_dev = pfdev->base.dev,
};
mmu->pgtbl_ops = alloc_io_pgtable_ops(fmt, &mmu->pgtbl_cfg, mmu);
@@ -848,7 +894,7 @@ static irqreturn_t panfrost_mmu_irq_handler_thread(int irq, void *data)
if (ret) {
/* terminal fault, print info about the fault */
dev_err(pfdev->dev,
dev_err(pfdev->base.dev,
"Unhandled Page fault in AS%d at VA 0x%016llX\n"
"Reason: %s\n"
"raw fault status: 0x%X\n"
@@ -896,18 +942,18 @@ int panfrost_mmu_init(struct panfrost_device *pfdev)
{
int err;
pfdev->mmu_irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "mmu");
pfdev->mmu_irq = platform_get_irq_byname(to_platform_device(pfdev->base.dev), "mmu");
if (pfdev->mmu_irq < 0)
return pfdev->mmu_irq;
err = devm_request_threaded_irq(pfdev->dev, pfdev->mmu_irq,
err = devm_request_threaded_irq(pfdev->base.dev, pfdev->mmu_irq,
panfrost_mmu_irq_handler,
panfrost_mmu_irq_handler_thread,
IRQF_SHARED, KBUILD_MODNAME "-mmu",
pfdev);
if (err) {
dev_err(pfdev->dev, "failed to request mmu irq");
dev_err(pfdev->base.dev, "failed to request mmu irq");
return err;
}

View File

@@ -4,6 +4,7 @@
#ifndef __PANFROST_MMU_H__
#define __PANFROST_MMU_H__
struct panfrost_device;
struct panfrost_gem_mapping;
struct panfrost_file_priv;
struct panfrost_mmu;
@@ -16,7 +17,7 @@ void panfrost_mmu_fini(struct panfrost_device *pfdev);
void panfrost_mmu_reset(struct panfrost_device *pfdev);
void panfrost_mmu_suspend_irq(struct panfrost_device *pfdev);
u32 panfrost_mmu_as_get(struct panfrost_device *pfdev, struct panfrost_mmu *mmu);
int panfrost_mmu_as_get(struct panfrost_device *pfdev, struct panfrost_mmu *mmu);
void panfrost_mmu_as_put(struct panfrost_device *pfdev, struct panfrost_mmu *mmu);
struct panfrost_mmu *panfrost_mmu_ctx_get(struct panfrost_mmu *mmu);

View File

@@ -84,11 +84,11 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
else if (perfcnt->user)
return -EBUSY;
ret = pm_runtime_get_sync(pfdev->dev);
ret = pm_runtime_get_sync(pfdev->base.dev);
if (ret < 0)
goto err_put_pm;
bo = drm_gem_shmem_create(pfdev->ddev, perfcnt->bosize);
bo = drm_gem_shmem_create(&pfdev->base, perfcnt->bosize);
if (IS_ERR(bo)) {
ret = PTR_ERR(bo);
goto err_put_pm;
@@ -130,9 +130,11 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
goto err_vunmap;
}
perfcnt->user = user;
ret = panfrost_mmu_as_get(pfdev, perfcnt->mapping->mmu);
if (ret < 0)
goto err_vunmap;
as = panfrost_mmu_as_get(pfdev, perfcnt->mapping->mmu);
as = ret;
cfg = GPU_PERFCNT_CFG_AS(as) |
GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_MANUAL);
@@ -164,6 +166,8 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
/* The BO ref is retained by the mapping. */
drm_gem_object_put(&bo->base);
perfcnt->user = user;
return 0;
err_vunmap:
@@ -175,7 +179,7 @@ err_close_bo:
err_put_bo:
drm_gem_object_put(&bo->base);
err_put_pm:
pm_runtime_put(pfdev->dev);
pm_runtime_put(pfdev->base.dev);
return ret;
}
@@ -203,7 +207,7 @@ static int panfrost_perfcnt_disable_locked(struct panfrost_device *pfdev,
panfrost_mmu_as_put(pfdev, perfcnt->mapping->mmu);
panfrost_gem_mapping_put(perfcnt->mapping);
perfcnt->mapping = NULL;
pm_runtime_put_autosuspend(pfdev->dev);
pm_runtime_put_autosuspend(pfdev->base.dev);
return 0;
}
@@ -211,7 +215,7 @@ static int panfrost_perfcnt_disable_locked(struct panfrost_device *pfdev,
int panfrost_ioctl_perfcnt_enable(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct panfrost_device *pfdev = dev->dev_private;
struct panfrost_device *pfdev = to_panfrost_device(dev);
struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
struct drm_panfrost_perfcnt_enable *req = data;
int ret;
@@ -238,7 +242,7 @@ int panfrost_ioctl_perfcnt_enable(struct drm_device *dev, void *data,
int panfrost_ioctl_perfcnt_dump(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct panfrost_device *pfdev = dev->dev_private;
struct panfrost_device *pfdev = to_panfrost_device(dev);
struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
struct drm_panfrost_perfcnt_dump *req = data;
void __user *user_ptr = (void __user *)(uintptr_t)req->buf_ptr;
@@ -273,12 +277,12 @@ void panfrost_perfcnt_close(struct drm_file *file_priv)
struct panfrost_device *pfdev = pfile->pfdev;
struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
pm_runtime_get_sync(pfdev->dev);
pm_runtime_get_sync(pfdev->base.dev);
mutex_lock(&perfcnt->lock);
if (perfcnt->user == pfile)
panfrost_perfcnt_disable_locked(pfdev, file_priv);
mutex_unlock(&perfcnt->lock);
pm_runtime_put_autosuspend(pfdev->dev);
pm_runtime_put_autosuspend(pfdev->base.dev);
}
int panfrost_perfcnt_init(struct panfrost_device *pfdev)
@@ -316,7 +320,7 @@ int panfrost_perfcnt_init(struct panfrost_device *pfdev)
COUNTERS_PER_BLOCK * BYTES_PER_COUNTER;
}
perfcnt = devm_kzalloc(pfdev->dev, sizeof(*perfcnt), GFP_KERNEL);
perfcnt = devm_kzalloc(pfdev->base.dev, sizeof(*perfcnt), GFP_KERNEL);
if (!perfcnt)
return -ENOMEM;

View File

@@ -146,10 +146,9 @@ int panthor_devfreq_init(struct panthor_device *ptdev)
ptdev->devfreq = pdevfreq;
ret = devm_pm_opp_set_regulators(dev, reg_names);
if (ret) {
if (ret && ret != -ENODEV) {
if (ret != -EPROBE_DEFER)
DRM_DEV_ERROR(dev, "Couldn't set OPP regulators\n");
return ret;
}

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