mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
drm-misc-next for v7.5:
UAPI Changes: - Add Apple Interchange fourcc. - Expose amdxdna busy time via DRM fdinfo. Cross-subsystem Changes: - Improve DT bindings for display/ste,mcde - Add kunit test for dma_fence_dedup_array() to dma-buf/test. Core Changes: - Documentation updates to drm/scheduler, gpu/buddy. - Fail kmapping a bo without pages. Driver Changes: - Bugfixes and improvements to panel/Raystar RFF500F-AWH-DNN, accel/ivpu, vc4, accel/amdxdna, panthor, nouveau, panfrost, panthor, accel/qaic, accel/rocket, bridge/lontium-lt8713sx, appletbdrm. - Add support for BOE Novatek NT51021, Retroid Pocket 6, Raydium RM69220 DDIC panels, Sharp LQ138P1JX61 eDP, BOE NV140FHD-N43, AUO B140HAN04.0, AUO 0x0db3, panels. - Add support for Mali-G68 to panfrost. - Add Chrontel CH7218A to bridge/simple. - Support ARGB8888 for virtio primary planes. - Improve panfrost gpu reset handling and initialization. - Add HDMI 2.0 support to rockchip/dw-hdmi-qp and improve HPD handling. - Advertise HDMI 1.2 capabilities in sun4i, bridge/adv7511, it66121 & inno-hdmi. - Advertise HDMI 1.3 capabilities in bridge/ite-6263. - Advertise HDMI 1.4 capabilities in bridge/lt9611 & rockchip/rk3066_hdmi - Switch many drivers to drm_atomic_helper_create_state in preparation for readout. -----BEGIN PGP SIGNATURE----- iQIyBAABCgAdFiEEuXvWqAysSYEJGuVH/lWMcqZwE8MFAmrSUDAACgkQ/lWMcqZw E8MTgA/2LBcj6jWpAGHHsGhGdsI62JIo1tmq7MoyUQyyfYDrnEhxqu5XPljpzcEk EbPywLgf04Fo2tbJ2jrb7PDwzTD0xmQn56ZZmvIBF9VtVW+HYUfhAQlBW3cWEzbo qZZvglpnzqJIQn0OLUiaTkaXsQLIHPzeGFEL+KHPXVdlwf3iM82ZZI9fH6tTIQWv FH8SHG5cVKIpdKcgVbNlYoyQSvA+oAg9wyrieRmyjCHFGkDl2PkNEuJJeNHpmacG 0XKugwgm9drsoHTwoWPVFeLWDBkCjGEZ+o+5QTQnYEd7bUq92auS2jk+DRS3HbZ0 +h7rUL4/8WgYM96o8ilcXnTE19YtvweDzt+/iUdhN9hAxj2c4c5rFoVkV2hPTOIk sM0Fs2NbO0Oj2wSRorRgtEL//8umSrA0n5xMoglVqtfQeZn2lBxvWkq+bHyPu9xc v8FxEA0Tyq4coibhuugt3fiOento2S0zhJQ/QIHxwol/JdL0VdYknNtzODcrEkji pkkCQxGexI181sD34rS3sG54L3dQpWO8hjH5udMwe7zk0ObcgSPsBzkX3xUN+qC+ yx4UbbxulUy9Dl/OACo0vI4ab5JwUbBrVpnOqJ53UH+nTEtNmDdfdU/frdbhp71z ntaMOJZdoRd2iXVGXbpXnzTWmrQiYzxDG7VJDk86KQucud2jtg== =VWtd -----END PGP SIGNATURE----- Merge tag 'drm-misc-next-2026-10-16' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next drm-misc-next for v7.5: UAPI Changes: - Add Apple Interchange fourcc. - Expose amdxdna busy time via DRM fdinfo. Cross-subsystem Changes: - Improve DT bindings for display/ste,mcde - Add kunit test for dma_fence_dedup_array() to dma-buf/test. Core Changes: - Documentation updates to drm/scheduler, gpu/buddy. - Fail kmapping a bo without pages. Driver Changes: - Bugfixes and improvements to panel/Raystar RFF500F-AWH-DNN, accel/ivpu, vc4, accel/amdxdna, panthor, nouveau, panfrost, panthor, accel/qaic, accel/rocket, bridge/lontium-lt8713sx, appletbdrm. - Add support for BOE Novatek NT51021, Retroid Pocket 6, Raydium RM69220 DDIC panels, Sharp LQ138P1JX61 eDP, BOE NV140FHD-N43, AUO B140HAN04.0, AUO 0x0db3, panels. - Add support for Mali-G68 to panfrost. - Add Chrontel CH7218A to bridge/simple. - Support ARGB8888 for virtio primary planes. - Improve panfrost gpu reset handling and initialization. - Add HDMI 2.0 support to rockchip/dw-hdmi-qp and improve HPD handling. - Advertise HDMI 1.2 capabilities in sun4i, bridge/adv7511, it66121 & inno-hdmi. - Advertise HDMI 1.3 capabilities in bridge/ite-6263. - Advertise HDMI 1.4 capabilities in bridge/lt9611 & rockchip/rk3066_hdmi - Switch many drivers to drm_atomic_helper_create_state in preparation for readout. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Link: https://patch.msgid.link/75e7de61-048c-4fdd-9ad2-6b47b29a4863@linux.intel.com
This commit is contained in:
commit
fad06cfaf3
|
|
@ -289,6 +289,7 @@ Example of the output showing the implemented key value pairs:
|
|||
drm-driver: amdxdna_accel_driver
|
||||
drm-client-id: 3219
|
||||
drm-pdev: 0000:c5:00.1
|
||||
drm-engine-npu: 14003870 ns
|
||||
amdxdna_accel_driver-heap-alloc: 60 KiB
|
||||
amdxdna_accel_driver-internal-alloc: 67588 KiB
|
||||
amdxdna_accel_driver-external-alloc: 0
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ properties:
|
|||
- adi,adv7123
|
||||
- algoltek,ag6311
|
||||
- asl-tek,cs5263
|
||||
- chrontel,ch7218a
|
||||
- dumb-vga-dac
|
||||
- mstar,tsumu88adt3-lf-1
|
||||
- parade,ps185hdm
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/novatek,nt51021.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Novatek NT51021 based DSI display Panels
|
||||
|
||||
maintainers:
|
||||
- Nickolay Goppen <setotau@mainlining.org>
|
||||
|
||||
description:
|
||||
The NT51021 IC from Novatek is a generic DSI Panel IC used to drive dsi
|
||||
panels.
|
||||
Right now, support is added only for a BOE WUXGA LCD display panels with a
|
||||
resolution of 1200x1920. They are video mode DSI panels.
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- boe,tv101wum-nm0
|
||||
- boe,tv101wum-nx0
|
||||
- boe,tv080wum-nx2
|
||||
- const: novatek,nt51021
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
description: phandle of gpio for reset line - This should be 8mA, gpio
|
||||
can be configured using mux, pinctrl, pinctrl-names (active low)
|
||||
|
||||
vdd-supply:
|
||||
description: phandle of the regulator that provides the supply voltage
|
||||
for digital circuits
|
||||
|
||||
avdd-supply:
|
||||
description: phandle of the regulator that provides the supply voltage
|
||||
for analog circuits
|
||||
|
||||
havdd-supply:
|
||||
description: phandle of the regulator that provides the supply voltage
|
||||
for analog circuits
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vdd-supply
|
||||
- avdd-supply
|
||||
- havdd-supply
|
||||
- reset-gpios
|
||||
- port
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
dsi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
panel@0 {
|
||||
compatible = "boe,tv101wum-nx0", "novatek,nt51021";
|
||||
reg = <0>;
|
||||
vdd-supply = <&lcd_pwr>;
|
||||
avdd-supply = <&lcd_pwr>;
|
||||
havdd-supply = <&lcd_pwr>;
|
||||
|
||||
backlight = <&i2c_backlight>;
|
||||
reset-gpios = <&tlmm 62 GPIO_ACTIVE_LOW>;
|
||||
|
||||
port {
|
||||
panel_in: endpoint {
|
||||
remote-endpoint = <&dsi0_out>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/raydium,rm69220.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Raydium RM69220 based MIPI-DSI panels
|
||||
|
||||
maintainers:
|
||||
- Alexander Koskovich <akoskovich@pm.me>
|
||||
|
||||
description:
|
||||
The Raydium RM69220 is a generic DSI Panel IC used to control
|
||||
AMOLED panels.
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- boe,bf068mwm-td0
|
||||
- const: raydium,rm69220
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
dvdd-supply:
|
||||
description: Digital voltage rail
|
||||
|
||||
vci-supply:
|
||||
description: Analog voltage rail
|
||||
|
||||
vddio-supply:
|
||||
description: I/O voltage rail
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- dvdd-supply
|
||||
- vci-supply
|
||||
- vddio-supply
|
||||
- reset-gpios
|
||||
- port
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
dsi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
panel@0 {
|
||||
compatible = "boe,bf068mwm-td0", "raydium,rm69220";
|
||||
reg = <0>;
|
||||
|
||||
reset-gpios = <&tlmm 12 GPIO_ACTIVE_LOW>;
|
||||
dvdd-supply = <&vreg_oled_dvdd_1p8>;
|
||||
vci-supply = <&vreg_l19b>;
|
||||
vddio-supply = <&vreg_l9b>;
|
||||
|
||||
port {
|
||||
panel_in_0: endpoint {
|
||||
remote-endpoint = <&dsi0_out>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
|
|
@ -14,7 +14,11 @@ allOf:
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
const: visionox,vtdr6130
|
||||
oneOf:
|
||||
- const: visionox,vtdr6130
|
||||
- items:
|
||||
- const: retroidpocket,rp6-panel
|
||||
- const: visionox,vtdr6130
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
@ -25,13 +29,13 @@ properties:
|
|||
vdd-supply: true
|
||||
port: true
|
||||
reset-gpios: true
|
||||
rotation: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vddio-supply
|
||||
- vci-supply
|
||||
- vdd-supply
|
||||
- reset-gpios
|
||||
- port
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ properties:
|
|||
resets:
|
||||
maxItems: 1
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
epod-supply:
|
||||
description: a phandle to the EPOD regulator
|
||||
|
||||
|
|
@ -109,6 +112,7 @@ examples:
|
|||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/arm/ux500_pm_domains.h>
|
||||
#include <dt-bindings/mfd/dbx500-prcmu.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
|
|
@ -116,6 +120,7 @@ examples:
|
|||
compatible = "ste,mcde";
|
||||
reg = <0xa0350000 0x1000>;
|
||||
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
|
||||
power-domains = <&pm_domains DOMAIN_B2R2_MCDE>;
|
||||
epod-supply = <&db8500_b2r2_mcde_reg>;
|
||||
vana-supply = <&ab8500_ldo_ana_reg>;
|
||||
clocks = <&prcmu_clk PRCMU_MCDECLK>,
|
||||
|
|
|
|||
13
MAINTAINERS
13
MAINTAINERS
|
|
@ -8368,6 +8368,13 @@ S: Maintained
|
|||
F: Documentation/devicetree/bindings/display/panel/novatek,nt37801.yaml
|
||||
F: drivers/gpu/drm/panel/panel-novatek-nt37801.c
|
||||
|
||||
DRM DRIVER FOR NOVATEK NT51021 PANELS
|
||||
M: Ryan Brue <ryanbrue.dev@gmail.com>
|
||||
M: Nickolay Goppen <setotau@mainlining.org>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/display/panel/novatek,nt51021.yaml
|
||||
F: drivers/gpu/drm/panel/panel-novatek-nt51021.c
|
||||
|
||||
DRM DRIVER FOR NVIDIA GEFORCE/QUADRO GPUS
|
||||
M: Lyude Paul <lyude@redhat.com>
|
||||
M: Danilo Krummrich <dakr@kernel.org>
|
||||
|
|
@ -8457,6 +8464,12 @@ S: Maintained
|
|||
F: Documentation/devicetree/bindings/display/panel/raydium,rm67191.yaml
|
||||
F: drivers/gpu/drm/panel/panel-raydium-rm67191.c
|
||||
|
||||
DRM DRIVER FOR RAYDIUM RM69220 PANELS
|
||||
M: Alexander Koskovich <akoskovich@pm.me>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/display/panel/raydium,rm69220.yaml
|
||||
F: drivers/gpu/drm/panel/panel-raydium-rm69220.c
|
||||
|
||||
DRM DRIVER FOR SAMSUNG DB7430 PANELS
|
||||
M: Linus Walleij <linusw@kernel.org>
|
||||
S: Maintained
|
||||
|
|
|
|||
|
|
@ -118,6 +118,45 @@ void amdxdna_vbnv_init(struct amdxdna_dev *xdna)
|
|||
amdxdna_update_vbnv(xdna, info->rev_vbnv_tbl, rev);
|
||||
}
|
||||
|
||||
void amdxdna_io_stats_job_start(struct amdxdna_client *client)
|
||||
{
|
||||
int depth;
|
||||
|
||||
guard(spinlock)(&client->io_stats.lock);
|
||||
|
||||
depth = client->io_stats.job_depth++;
|
||||
if (!depth)
|
||||
client->io_stats.start_time = ktime_get_ns();
|
||||
}
|
||||
|
||||
void amdxdna_io_stats_job_done(struct amdxdna_client *client)
|
||||
{
|
||||
u64 busy_ns;
|
||||
int depth;
|
||||
|
||||
guard(spinlock)(&client->io_stats.lock);
|
||||
|
||||
depth = --client->io_stats.job_depth;
|
||||
if (!depth) {
|
||||
busy_ns = ktime_get_ns() - client->io_stats.start_time;
|
||||
client->io_stats.start_time = 0;
|
||||
client->io_stats.busy_time += busy_ns;
|
||||
}
|
||||
}
|
||||
|
||||
u64 amdxdna_io_stats_busy_time_ns(struct amdxdna_client *client)
|
||||
{
|
||||
u64 busy_ns;
|
||||
|
||||
guard(spinlock)(&client->io_stats.lock);
|
||||
|
||||
busy_ns = client->io_stats.busy_time;
|
||||
if (client->io_stats.job_depth)
|
||||
busy_ns += ktime_get_ns() - client->io_stats.start_time;
|
||||
|
||||
return busy_ns;
|
||||
}
|
||||
|
||||
int amdxdna_get_metadata(struct aie_device *aie,
|
||||
struct amdxdna_client *client,
|
||||
struct amdxdna_drm_get_info *args)
|
||||
|
|
|
|||
|
|
@ -117,4 +117,8 @@ void aie_smu_fini(struct smu_device *smu);
|
|||
int aie_smu_set_clocks(struct smu_device *smu, u32 *npuclk, u32 *hclk);
|
||||
int aie_smu_set_dpm(struct smu_device *smu, u32 dpm_level);
|
||||
|
||||
void amdxdna_io_stats_job_start(struct amdxdna_client *client);
|
||||
void amdxdna_io_stats_job_done(struct amdxdna_client *client);
|
||||
u64 amdxdna_io_stats_busy_time_ns(struct amdxdna_client *client);
|
||||
|
||||
#endif /* _AIE_H_ */
|
||||
|
|
|
|||
|
|
@ -290,6 +290,7 @@ aie2_sched_resp_handler(void *handle, void __iomem *data, size_t size)
|
|||
int ret = 0;
|
||||
u32 status;
|
||||
|
||||
amdxdna_io_stats_job_done(job->hwctx->client);
|
||||
cmd_abo = job->cmd_bo;
|
||||
|
||||
if (unlikely(job->job_timeout)) {
|
||||
|
|
@ -322,6 +323,8 @@ aie2_sched_drvcmd_resp_handler(void *handle, void __iomem *data, size_t size)
|
|||
struct amdxdna_sched_job *job = handle;
|
||||
int ret = 0;
|
||||
|
||||
amdxdna_io_stats_job_done(job->hwctx->client);
|
||||
|
||||
if (unlikely(!data || size != sizeof(u32))) {
|
||||
job->drv_cmd->result = U32_MAX;
|
||||
ret = -EINVAL;
|
||||
|
|
@ -344,6 +347,7 @@ aie2_sched_cmdlist_resp_handler(void *handle, void __iomem *data, size_t size)
|
|||
u32 cmd_status;
|
||||
int ret = 0;
|
||||
|
||||
amdxdna_io_stats_job_done(job->hwctx->client);
|
||||
cmd_abo = job->cmd_bo;
|
||||
|
||||
if (unlikely(job->job_timeout)) {
|
||||
|
|
@ -405,6 +409,7 @@ aie2_sched_job_run(struct drm_sched_job *sched_job)
|
|||
kref_get(&job->refcnt);
|
||||
fence = dma_fence_get(job->fence);
|
||||
|
||||
amdxdna_io_stats_job_start(job->hwctx->client);
|
||||
if (job->drv_cmd) {
|
||||
switch (job->drv_cmd->opcode) {
|
||||
case SYNC_DEBUG_BO:
|
||||
|
|
@ -432,6 +437,7 @@ aie2_sched_job_run(struct drm_sched_job *sched_job)
|
|||
|
||||
out:
|
||||
if (ret) {
|
||||
amdxdna_io_stats_job_done(job->hwctx->client);
|
||||
dma_fence_put(job->fence);
|
||||
aie2_job_put(job);
|
||||
mmput(job->mm);
|
||||
|
|
|
|||
|
|
@ -343,15 +343,14 @@ void aie2_error_async_events_free(struct amdxdna_dev_hdl *ndev)
|
|||
kfree(events);
|
||||
}
|
||||
|
||||
int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev)
|
||||
int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev, u32 num_events)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
u32 total_col = ndev->total_col;
|
||||
u32 total_size = ASYNC_BUF_SIZE * total_col;
|
||||
u32 total_size = ASYNC_BUF_SIZE * num_events;
|
||||
struct async_events *events;
|
||||
int i, ret;
|
||||
|
||||
events = kzalloc_flex(*events, event, total_col);
|
||||
events = kzalloc_flex(*events, event, num_events);
|
||||
if (!events)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -361,7 +360,7 @@ int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev)
|
|||
goto free_events;
|
||||
}
|
||||
events->size = total_size;
|
||||
events->event_cnt = total_col;
|
||||
events->event_cnt = num_events;
|
||||
|
||||
events->wq = alloc_ordered_workqueue("async_wq", 0);
|
||||
if (!events->wq) {
|
||||
|
|
|
|||
|
|
@ -261,8 +261,9 @@ int aie2_create_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwct
|
|||
goto del_ctx_req;
|
||||
}
|
||||
|
||||
/* +1 for the config_cu message that can be in-flight concurrently */
|
||||
ret = xdna_mailbox_start_channel(hwctx->priv->mbox_chann, &x2i, &i2x,
|
||||
intr_reg, ret);
|
||||
intr_reg, ret, HWCTX_MAX_CMDS + 1);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Not able to create channel");
|
||||
ret = -EINVAL;
|
||||
|
|
@ -486,7 +487,7 @@ int aie2_register_asyn_event_msg(struct amdxdna_dev_hdl *ndev, dma_addr_t addr,
|
|||
req.buf_size = size;
|
||||
|
||||
XDNA_DBG(ndev->aie.xdna, "Register addr 0x%llx size 0x%x", addr, size);
|
||||
return xdna_mailbox_send_msg(ndev->aie.mgmt_chann, &msg, TX_TIMEOUT);
|
||||
return xdna_mailbox_send_msg(ndev->aie.mgmt_chann, &msg);
|
||||
}
|
||||
|
||||
int aie2_config_cu(struct amdxdna_hwctx *hwctx,
|
||||
|
|
@ -545,7 +546,8 @@ int aie2_config_cu(struct amdxdna_hwctx *hwctx,
|
|||
msg.handle = hwctx;
|
||||
msg.opcode = MSG_OP_CONFIG_CU;
|
||||
msg.notify_cb = notify_cb;
|
||||
return xdna_mailbox_send_msg(chann, &msg, TX_TIMEOUT);
|
||||
|
||||
return xdna_mailbox_send_msg(chann, &msg);
|
||||
}
|
||||
|
||||
static int aie2_init_exec_cu_req(struct amdxdna_gem_obj *cmd_bo, void *req,
|
||||
|
|
@ -950,7 +952,7 @@ int aie2_execbuf(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job,
|
|||
print_hex_dump_debug("cmd: ", DUMP_PREFIX_OFFSET, 16, 4, &req,
|
||||
0x40, false);
|
||||
|
||||
ret = xdna_mailbox_send_msg(chann, &msg, TX_TIMEOUT);
|
||||
ret = xdna_mailbox_send_msg(chann, &msg);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Send message failed");
|
||||
return ret;
|
||||
|
|
@ -1039,7 +1041,7 @@ int aie2_cmdlist_multi_execbuf(struct amdxdna_hwctx *hwctx,
|
|||
msg.send_size = sizeof(req);
|
||||
print_hex_dump_debug("cmdlist msg: ", DUMP_PREFIX_OFFSET, 16, 4,
|
||||
&req, msg.send_size, false);
|
||||
ret = xdna_mailbox_send_msg(chann, &msg, TX_TIMEOUT);
|
||||
ret = xdna_mailbox_send_msg(chann, &msg);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Send message failed");
|
||||
return ret;
|
||||
|
|
@ -1086,7 +1088,7 @@ int aie2_cmdlist_single_execbuf(struct amdxdna_hwctx *hwctx,
|
|||
msg.send_size = sizeof(req);
|
||||
print_hex_dump_debug("cmdlist msg: ", DUMP_PREFIX_OFFSET, 16, 4,
|
||||
&req, msg.send_size, false);
|
||||
ret = xdna_mailbox_send_msg(chann, &msg, TX_TIMEOUT);
|
||||
ret = xdna_mailbox_send_msg(chann, &msg);
|
||||
if (ret) {
|
||||
XDNA_ERR(hwctx->client->xdna, "Send message failed");
|
||||
return ret;
|
||||
|
|
@ -1122,7 +1124,7 @@ int aie2_sync_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job,
|
|||
msg.send_size = sizeof(req);
|
||||
msg.opcode = MSG_OP_SYNC_BO;
|
||||
|
||||
ret = xdna_mailbox_send_msg(chann, &msg, TX_TIMEOUT);
|
||||
ret = xdna_mailbox_send_msg(chann, &msg);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Send message failed");
|
||||
return ret;
|
||||
|
|
@ -1157,7 +1159,7 @@ int aie2_config_debug_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *
|
|||
msg.send_size = sizeof(req);
|
||||
msg.opcode = MSG_OP_CONFIG_DEBUG_BO;
|
||||
|
||||
return xdna_mailbox_send_msg(chann, &msg, TX_TIMEOUT);
|
||||
return xdna_mailbox_send_msg(chann, &msg);
|
||||
}
|
||||
|
||||
int aie2_query_app_health(struct amdxdna_dev_hdl *ndev, u32 context_id,
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "aie2_pci.h"
|
||||
#include "aie2_solver.h"
|
||||
#include "amdxdna_ctx.h"
|
||||
#include "amdxdna_error.h"
|
||||
#include "amdxdna_gem.h"
|
||||
#include "amdxdna_mailbox.h"
|
||||
#include "amdxdna_pci_drv.h"
|
||||
|
|
@ -385,11 +386,21 @@ static int aie2_hw_start(struct amdxdna_dev *xdna)
|
|||
}
|
||||
|
||||
xdna_mailbox_intr_reg = ndev->aie.mgmt_i2x.mb_head_ptr_reg + 4;
|
||||
/*
|
||||
* At most AMDXDNA_MAX_ASYNC_EVENT_BUFS async event messages plus one
|
||||
* management command can be unresponded. The async slots stay busy
|
||||
* until firmware reports an error. Every management command holds
|
||||
* dev_lock across aie_send_mgmt_msg_wait(), and the response clears
|
||||
* the slot before that wait returns, so a second ioctl blocks on
|
||||
* dev_lock rather than observing -ENOBUFS. Async re-registration
|
||||
* takes the same lock after the RX path has freed its slot.
|
||||
*/
|
||||
ret = xdna_mailbox_start_channel(ndev->aie.mgmt_chann,
|
||||
&ndev->aie.mgmt_x2i,
|
||||
&ndev->aie.mgmt_i2x,
|
||||
xdna_mailbox_intr_reg,
|
||||
mgmt_mb_irq);
|
||||
mgmt_mb_irq,
|
||||
AMDXDNA_MAX_ASYNC_EVENT_BUFS + 1);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "failed to start management mailbox channel");
|
||||
ret = -EINVAL;
|
||||
|
|
@ -414,7 +425,7 @@ static int aie2_hw_start(struct amdxdna_dev *xdna)
|
|||
goto stop_fw;
|
||||
}
|
||||
|
||||
ret = aie2_error_async_events_alloc(ndev);
|
||||
ret = aie2_error_async_events_alloc(ndev, AMDXDNA_MAX_ASYNC_EVENT_BUFS);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Allocate async events failed, ret %d", ret);
|
||||
goto stop_fw;
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ int aie2_pm_set_mode(struct amdxdna_dev_hdl *ndev, enum amdxdna_power_mode_type
|
|||
int aie2_pm_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level);
|
||||
|
||||
/* aie2_error.c */
|
||||
int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev);
|
||||
int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev, u32 num_events);
|
||||
void aie2_error_async_events_free(struct amdxdna_dev_hdl *ndev);
|
||||
int aie2_error_async_msg_thread(void *data);
|
||||
int aie2_get_array_async_error(struct amdxdna_dev_hdl *ndev,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include "aie.h"
|
||||
#include "aie4_msg_priv.h"
|
||||
#include "aie4_pci.h"
|
||||
#include "amdxdna_error.h"
|
||||
#include "amdxdna_mailbox.h"
|
||||
#include "amdxdna_mailbox_helper.h"
|
||||
#include "amdxdna_pci_drv.h"
|
||||
|
|
@ -181,11 +182,16 @@ static int aie4_mailbox_start(struct amdxdna_dev *xdna,
|
|||
goto free_channel;
|
||||
}
|
||||
|
||||
/*
|
||||
* At any given time, at most AMDXDNA_MAX_ASYNC_EVENT_BUFS async event
|
||||
* messages plus 1 other management command can be unresponded.
|
||||
*/
|
||||
ret = xdna_mailbox_start_channel(ndev->aie.mgmt_chann,
|
||||
&ndev->aie.mgmt_x2i,
|
||||
&ndev->aie.mgmt_i2x,
|
||||
NO_IOHUB,
|
||||
mgmt_mb_irq);
|
||||
mgmt_mb_irq,
|
||||
AMDXDNA_MAX_ASYNC_EVENT_BUFS + 1);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "failed to start management mailbox channel");
|
||||
ret = -EINVAL;
|
||||
|
|
|
|||
|
|
@ -56,4 +56,14 @@ enum amdxdna_error_module {
|
|||
(FIELD_PREP(AMDXDNA_EXTRA_ERR_COL_MASK, col) | \
|
||||
FIELD_PREP(AMDXDNA_EXTRA_ERR_ROW_MASK, row))
|
||||
|
||||
/*
|
||||
* Maximum number of async event buffers. This value is used in two places:
|
||||
* (1) to size the management mailbox channel, which must happen before
|
||||
* total_col is known from firmware; (2) to allocate the async event pool,
|
||||
* which runs after total_col is known. Both counts must match. The channel
|
||||
* is sized AMDXDNA_MAX_ASYNC_EVENT_BUFS + 1 (one extra for other management
|
||||
* commands), so the pool cannot exceed AMDXDNA_MAX_ASYNC_EVENT_BUFS slots.
|
||||
*/
|
||||
#define AMDXDNA_MAX_ASYNC_EVENT_BUFS 4
|
||||
|
||||
#endif /* _AMDXDNA_ERROR_H_ */
|
||||
|
|
|
|||
|
|
@ -1140,6 +1140,11 @@ amdxdna_drm_create_dev_heap_bo(struct drm_device *dev,
|
|||
struct amdxdna_gem_obj *abo;
|
||||
int ret;
|
||||
|
||||
if (!xdna->dev_info->dev_mem_size) {
|
||||
XDNA_DBG(xdna, "Device heap is not supported");
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
WARN_ON(!is_power_of_2(xdna->dev_info->dev_mem_size));
|
||||
XDNA_DBG(xdna, "Requested dev heap size 0x%llx", args->size);
|
||||
if (!args->size || !IS_ALIGNED(args->size, xdna->dev_info->dev_mem_size)) {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/xarray.h>
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/amdxdna.h>
|
||||
|
|
@ -35,9 +34,12 @@
|
|||
(_chann)->msix_irq, ##args); \
|
||||
})
|
||||
|
||||
#define MSG_BUF_SZ(chann) \
|
||||
(mailbox_get_ringbuf_size(chann, CHAN_RES_X2I) + \
|
||||
sizeof(struct mailbox_msg))
|
||||
|
||||
#define MAGIC_VAL 0x1D000000U
|
||||
#define MAGIC_VAL_MASK 0xFF000000
|
||||
#define MAX_MSG_ID_ENTRIES 256
|
||||
#define MSG_RX_TIMER 200 /* milliseconds */
|
||||
#define MAILBOX_NAME "xdna_mailbox"
|
||||
|
||||
|
|
@ -57,8 +59,6 @@ struct mailbox_channel {
|
|||
struct xdna_mailbox_chann_res res[CHAN_RES_NUM];
|
||||
int msix_irq;
|
||||
u32 iohub_int_addr;
|
||||
struct xarray chan_xa;
|
||||
u32 next_msgid;
|
||||
u32 x2i_tail;
|
||||
|
||||
/* Received msg related fields */
|
||||
|
|
@ -66,6 +66,12 @@ struct mailbox_channel {
|
|||
struct work_struct rx_work;
|
||||
u32 i2x_head;
|
||||
bool bad_state;
|
||||
|
||||
/* Pre-allocated message buffer pool */
|
||||
void *msg_buf;
|
||||
u32 msg_buf_num;
|
||||
u32 next_slot; /* next slot index to try for allocation */
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
#define MSG_BODY_SZ GENMASK(10, 0)
|
||||
|
|
@ -90,12 +96,36 @@ struct mailbox_pkg {
|
|||
#define TOMBSTONE 0xDEADFACE
|
||||
|
||||
struct mailbox_msg {
|
||||
bool busy;
|
||||
void *handle;
|
||||
int (*notify_cb)(void *handle, void __iomem *data, size_t size);
|
||||
size_t pkg_size; /* package size in bytes */
|
||||
struct mailbox_pkg pkg;
|
||||
};
|
||||
|
||||
/*
|
||||
* Clear busy before invoking the callback so that a new submission can
|
||||
* reuse the slot immediately - by the time notify_cb returns, the caller
|
||||
* may already have submitted a new job that needs this slot.
|
||||
*
|
||||
* notify_cb and handle are cached in locals first. smp_store_release()
|
||||
* ensures those loads complete before busy is cleared - without it the
|
||||
* compiler or CPU could sink the loads past the store, letting a
|
||||
* concurrent sender overwrite notify_cb/handle before we read them.
|
||||
* Paired with smp_load_acquire() in mailbox_acquire_msgid().
|
||||
*/
|
||||
static int mailbox_msg_done(struct mailbox_msg *mb_msg, void __iomem *data, size_t size)
|
||||
{
|
||||
int (*notify_cb)(void *, void __iomem *, size_t) = mb_msg->notify_cb;
|
||||
void *handle = mb_msg->handle;
|
||||
|
||||
/* Pairs with smp_load_acquire() in mailbox_acquire_msgid(). */
|
||||
smp_store_release(&mb_msg->busy, false);
|
||||
if (notify_cb)
|
||||
return notify_cb(handle, data, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mailbox_reg_write(struct mailbox_channel *mb_chann, u32 mbox_reg, u32 data)
|
||||
{
|
||||
struct xdna_mailbox_res *mb_res = &mb_chann->mb->res;
|
||||
|
|
@ -161,38 +191,57 @@ static inline int mailbox_validate_msgid(int msg_id)
|
|||
return (msg_id & MAGIC_VAL_MASK) == MAGIC_VAL;
|
||||
}
|
||||
|
||||
static int mailbox_acquire_msgid(struct mailbox_channel *mb_chann, struct mailbox_msg *mb_msg)
|
||||
static struct mailbox_msg *mailbox_msg_ptr(struct mailbox_channel *mb_chann, u32 slot)
|
||||
{
|
||||
u32 msg_id;
|
||||
int ret;
|
||||
return mb_chann->msg_buf + slot * MSG_BUF_SZ(mb_chann);
|
||||
}
|
||||
|
||||
ret = xa_alloc_cyclic_irq(&mb_chann->chan_xa, &msg_id, mb_msg,
|
||||
XA_LIMIT(0, MAX_MSG_ID_ENTRIES - 1),
|
||||
&mb_chann->next_msgid, GFP_NOWAIT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
static int mailbox_acquire_msgid(struct mailbox_channel *mb_chann)
|
||||
{
|
||||
struct mailbox_msg *mb_msg;
|
||||
u32 slot;
|
||||
u32 i;
|
||||
|
||||
/*
|
||||
* Add MAGIC_VAL to the higher bits.
|
||||
* msg_id = slot | MAGIC_VAL. Scan slots starting from next_slot.
|
||||
* smp_load_acquire() pairs with smp_store_release() in mailbox_msg_done()
|
||||
* to ensure that once we observe busy == false, notify_cb and handle are
|
||||
* also visible as their post-completion values before we overwrite them.
|
||||
*/
|
||||
msg_id |= MAGIC_VAL;
|
||||
return msg_id;
|
||||
for (i = 0; i < mb_chann->msg_buf_num; i++) {
|
||||
slot = (mb_chann->next_slot + i) % mb_chann->msg_buf_num;
|
||||
mb_msg = mailbox_msg_ptr(mb_chann, slot);
|
||||
/* Pairs with smp_store_release() in mailbox_msg_done(). */
|
||||
if (!smp_load_acquire(&mb_msg->busy)) {
|
||||
mb_chann->next_slot = (slot + 1) % mb_chann->msg_buf_num;
|
||||
return slot | MAGIC_VAL;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
static void mailbox_release_msgid(struct mailbox_channel *mb_chann, int msg_id)
|
||||
static struct mailbox_msg *mailbox_get_msg_buf(struct mailbox_channel *mb_chann,
|
||||
size_t msg_size)
|
||||
{
|
||||
msg_id &= ~MAGIC_VAL_MASK;
|
||||
xa_erase_irq(&mb_chann->chan_xa, msg_id);
|
||||
}
|
||||
struct mailbox_msg *mb_msg;
|
||||
int msg_id;
|
||||
u32 slot;
|
||||
|
||||
static void mailbox_release_msg(struct mailbox_channel *mb_chann,
|
||||
struct mailbox_msg *mb_msg)
|
||||
{
|
||||
MB_DBG(mb_chann, "msg_id 0x%x msg opcode 0x%x",
|
||||
mb_msg->pkg.header.id, mb_msg->pkg.header.opcode);
|
||||
if (mb_msg->notify_cb)
|
||||
mb_msg->notify_cb(mb_msg->handle, NULL, 0);
|
||||
kfree(mb_msg);
|
||||
/* msg_id = slot | MAGIC_VAL */
|
||||
msg_id = mailbox_acquire_msgid(mb_chann);
|
||||
if (msg_id < 0) {
|
||||
MB_ERR(mb_chann, "No free message slot");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
slot = msg_id & ~MAGIC_VAL_MASK;
|
||||
mb_msg = mailbox_msg_ptr(mb_chann, slot);
|
||||
memset(mb_msg, 0, msg_size + sizeof(*mb_msg));
|
||||
mb_msg->busy = true;
|
||||
mb_msg->pkg.header.id = msg_id;
|
||||
|
||||
return mb_msg;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -224,7 +273,7 @@ mailbox_send_msg(struct mailbox_channel *mb_chann, struct mailbox_msg *mb_msg)
|
|||
if (tail < head && tmp_tail >= head) {
|
||||
ret = read_poll_timeout(mailbox_get_headptr, head,
|
||||
tmp_tail < head || tail >= head,
|
||||
1, 100, false, mb_chann, CHAN_RES_X2I);
|
||||
1, 2000000, false, mb_chann, CHAN_RES_X2I);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -248,8 +297,9 @@ mailbox_get_resp(struct mailbox_channel *mb_chann, struct xdna_msg_header *heade
|
|||
void __iomem *data)
|
||||
{
|
||||
struct mailbox_msg *mb_msg;
|
||||
int msg_id;
|
||||
int ret = 0;
|
||||
int msg_id;
|
||||
u32 slot;
|
||||
|
||||
msg_id = header->id;
|
||||
if (!mailbox_validate_msgid(msg_id)) {
|
||||
|
|
@ -257,22 +307,32 @@ mailbox_get_resp(struct mailbox_channel *mb_chann, struct xdna_msg_header *heade
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
msg_id &= ~MAGIC_VAL_MASK;
|
||||
mb_msg = xa_erase_irq(&mb_chann->chan_xa, msg_id);
|
||||
if (!mb_msg) {
|
||||
MB_ERR(mb_chann, "Cannot find msg 0x%x", msg_id);
|
||||
slot = msg_id & ~MAGIC_VAL_MASK;
|
||||
if (unlikely(slot >= mb_chann->msg_buf_num)) {
|
||||
MB_ERR(mb_chann, "Invalid msg_id 0x%x", msg_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
mb_msg = mailbox_msg_ptr(mb_chann, slot);
|
||||
|
||||
MB_DBG(mb_chann, "opcode 0x%x size %d id 0x%x",
|
||||
header->opcode, header->total_size, header->id);
|
||||
if (mb_msg->notify_cb) {
|
||||
ret = mb_msg->notify_cb(mb_msg->handle, data, header->total_size);
|
||||
if (unlikely(ret))
|
||||
MB_ERR(mb_chann, "Message callback ret %d", ret);
|
||||
|
||||
/*
|
||||
* msg_id is slot | MAGIC_VAL and is reused as soon as the slot is
|
||||
* freed. The management firmware protocol guarantees exactly one
|
||||
* response for each request, so a response cannot refer to a previous
|
||||
* user of a reused slot. Keep the busy check as a defensive guard
|
||||
* against an unexpected response for an idle slot.
|
||||
*/
|
||||
if (unlikely(!mb_msg->busy)) {
|
||||
MB_WARN_ONCE(mb_chann, "Unexpected response for idle slot 0x%x", msg_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
kfree(mb_msg);
|
||||
ret = mailbox_msg_done(mb_msg, data, header->total_size);
|
||||
if (unlikely(ret))
|
||||
MB_ERR(mb_chann, "Message callback ret %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -399,7 +459,7 @@ static void mailbox_rx_worker(struct work_struct *rx_work)
|
|||
}
|
||||
|
||||
int xdna_mailbox_send_msg(struct mailbox_channel *mb_chann,
|
||||
const struct xdna_mailbox_msg *msg, u64 tx_timeout)
|
||||
const struct xdna_mailbox_msg *msg)
|
||||
{
|
||||
struct xdna_msg_header *header;
|
||||
struct mailbox_msg *mb_msg;
|
||||
|
|
@ -428,9 +488,12 @@ int xdna_mailbox_send_msg(struct mailbox_channel *mb_chann,
|
|||
return -EPIPE;
|
||||
}
|
||||
|
||||
mb_msg = kzalloc(sizeof(*mb_msg) + pkg_size, GFP_KERNEL);
|
||||
if (!mb_msg)
|
||||
return -ENOMEM;
|
||||
mutex_lock(&mb_chann->lock);
|
||||
mb_msg = mailbox_get_msg_buf(mb_chann, pkg_size);
|
||||
if (!mb_msg) {
|
||||
mutex_unlock(&mb_chann->lock);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
mb_msg->handle = msg->handle;
|
||||
mb_msg->notify_cb = msg->notify_cb;
|
||||
|
|
@ -447,28 +510,18 @@ int xdna_mailbox_send_msg(struct mailbox_channel *mb_chann,
|
|||
header->opcode = msg->opcode;
|
||||
memcpy(mb_msg->pkg.payload, msg->send_data, msg->send_size);
|
||||
|
||||
ret = mailbox_acquire_msgid(mb_chann, mb_msg);
|
||||
if (unlikely(ret < 0)) {
|
||||
MB_ERR(mb_chann, "mailbox_acquire_msgid failed");
|
||||
goto msg_id_failed;
|
||||
}
|
||||
header->id = ret;
|
||||
|
||||
MB_DBG(mb_chann, "opcode 0x%x size %d id 0x%x",
|
||||
header->opcode, header->total_size, header->id);
|
||||
|
||||
ret = mailbox_send_msg(mb_chann, mb_msg);
|
||||
if (ret) {
|
||||
MB_DBG(mb_chann, "Error in mailbox send msg, ret %d", ret);
|
||||
goto release_id;
|
||||
mb_msg->busy = false;
|
||||
mutex_unlock(&mb_chann->lock);
|
||||
return ret;
|
||||
}
|
||||
mutex_unlock(&mb_chann->lock);
|
||||
|
||||
return 0;
|
||||
|
||||
release_id:
|
||||
mailbox_release_msgid(mb_chann, header->id);
|
||||
msg_id_failed:
|
||||
kfree(mb_msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -487,6 +540,7 @@ struct mailbox_channel *xdna_mailbox_alloc_channel(struct mailbox *mb)
|
|||
goto free_chann;
|
||||
}
|
||||
mb_chann->mb = mb;
|
||||
mutex_init(&mb_chann->lock);
|
||||
|
||||
return mb_chann;
|
||||
|
||||
|
|
@ -500,7 +554,9 @@ void xdna_mailbox_free_channel(struct mailbox_channel *mb_chann)
|
|||
if (!mb_chann)
|
||||
return;
|
||||
|
||||
kfree(mb_chann->msg_buf);
|
||||
destroy_workqueue(mb_chann->work_q);
|
||||
mutex_destroy(&mb_chann->lock);
|
||||
kfree(mb_chann);
|
||||
}
|
||||
|
||||
|
|
@ -509,21 +565,32 @@ xdna_mailbox_start_channel(struct mailbox_channel *mb_chann,
|
|||
const struct xdna_mailbox_chann_res *x2i,
|
||||
const struct xdna_mailbox_chann_res *i2x,
|
||||
u32 iohub_int_addr,
|
||||
int mb_irq)
|
||||
int mb_irq, u32 n_msg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!is_power_of_2(x2i->rb_size) || !is_power_of_2(i2x->rb_size)) {
|
||||
pr_err("Ring buf size must be power of 2\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* The ring buffer geometry, rb_start_addr and rb_size for both the
|
||||
* x2i and the i2x channel, comes from AMD signed firmware, through
|
||||
* the management or mailbox information block, or through the
|
||||
* CREATE_CONTEXT response. The driver trusts those values by design
|
||||
* and does not bound them against the mapped region.
|
||||
*/
|
||||
mb_chann->msix_irq = mb_irq;
|
||||
mb_chann->iohub_int_addr = iohub_int_addr;
|
||||
memcpy(&mb_chann->res[CHAN_RES_X2I], x2i, sizeof(*x2i));
|
||||
memcpy(&mb_chann->res[CHAN_RES_I2X], i2x, sizeof(*i2x));
|
||||
|
||||
xa_init_flags(&mb_chann->chan_xa, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
|
||||
/*
|
||||
* msg_buf is a flat array of n_msg slots, separate from the hardware
|
||||
* ring buffer. Each slot is rb_size bytes - the combined size of the
|
||||
* mailbox_msg metadata and the package payload must not exceed rb_size.
|
||||
*/
|
||||
mb_chann->msg_buf = kcalloc(n_msg, MSG_BUF_SZ(mb_chann), GFP_KERNEL);
|
||||
if (!mb_chann->msg_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
mb_chann->msg_buf_num = n_msg;
|
||||
mb_chann->x2i_tail = mailbox_get_tailptr(mb_chann, CHAN_RES_X2I);
|
||||
mb_chann->i2x_head = mailbox_get_headptr(mb_chann, CHAN_RES_I2X);
|
||||
|
||||
|
|
@ -531,6 +598,8 @@ xdna_mailbox_start_channel(struct mailbox_channel *mb_chann,
|
|||
ret = request_irq(mb_irq, mailbox_irq_handler, 0, MAILBOX_NAME, mb_chann);
|
||||
if (ret) {
|
||||
MB_ERR(mb_chann, "Failed to request irq %d ret %d", mb_irq, ret);
|
||||
kfree(mb_chann->msg_buf);
|
||||
mb_chann->msg_buf = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -544,7 +613,7 @@ xdna_mailbox_start_channel(struct mailbox_channel *mb_chann,
|
|||
void xdna_mailbox_stop_channel(struct mailbox_channel *mb_chann)
|
||||
{
|
||||
struct mailbox_msg *mb_msg;
|
||||
unsigned long msg_id;
|
||||
u32 i;
|
||||
|
||||
if (!mb_chann)
|
||||
return;
|
||||
|
|
@ -555,12 +624,22 @@ void xdna_mailbox_stop_channel(struct mailbox_channel *mb_chann)
|
|||
/* Cancel RX work and wait for it to finish */
|
||||
drain_workqueue(mb_chann->work_q);
|
||||
|
||||
/* We can clean up and release resources */
|
||||
xa_for_each_start(&mb_chann->chan_xa, msg_id, mb_msg, mb_chann->next_msgid)
|
||||
mailbox_release_msg(mb_chann, mb_msg);
|
||||
xa_for_each_range(&mb_chann->chan_xa, msg_id, mb_msg, 0, mb_chann->next_msgid - 1)
|
||||
mailbox_release_msg(mb_chann, mb_msg);
|
||||
xa_destroy(&mb_chann->chan_xa);
|
||||
/* Release any in-flight messages in the pool
|
||||
*
|
||||
* Drain in submission order: next_slot points to the slot after
|
||||
* the most recently assigned one, so start from next_slot and
|
||||
* wrap around so callbacks fire oldest-first.
|
||||
*/
|
||||
for (i = 0; i < mb_chann->msg_buf_num; i++) {
|
||||
u32 slot = (mb_chann->next_slot + i) % mb_chann->msg_buf_num;
|
||||
|
||||
mb_msg = mailbox_msg_ptr(mb_chann, slot);
|
||||
if (!mb_msg->busy)
|
||||
continue;
|
||||
MB_DBG(mb_chann, "msg_id 0x%x msg opcode 0x%x",
|
||||
mb_msg->pkg.header.id, mb_msg->pkg.header.opcode);
|
||||
mailbox_msg_done(mb_msg, NULL, 0);
|
||||
}
|
||||
|
||||
MB_DBG(mb_chann, "Mailbox channel stopped, irq: %d", mb_chann->msix_irq);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,6 +88,10 @@ struct mailbox_channel *xdna_mailbox_alloc_channel(struct mailbox *mb);
|
|||
* @i2x: firmware to host mailbox resources
|
||||
* @xdna_mailbox_intr_reg: register addr of MSI-X interrupt
|
||||
* @mb_irq: Linux IRQ number associated with mailbox MSI-X interrupt vector index
|
||||
* @n_msg: number of message slots to pre-allocate; must be non-zero for
|
||||
* the PCI transport (the platform transport ignores this argument).
|
||||
* Each slot is rb_size bytes. The caller must ensure at most n_msg
|
||||
* messages are in flight at any time.
|
||||
*
|
||||
* Return: If success, return a handle of mailbox channel. Otherwise, return NULL.
|
||||
*/
|
||||
|
|
@ -96,7 +100,7 @@ xdna_mailbox_start_channel(struct mailbox_channel *mb_chann,
|
|||
const struct xdna_mailbox_chann_res *x2i,
|
||||
const struct xdna_mailbox_chann_res *i2x,
|
||||
u32 xdna_mailbox_intr_reg,
|
||||
int mb_irq);
|
||||
int mb_irq, u32 n_msg);
|
||||
|
||||
/*
|
||||
* xdna_mailbox_free_channel() -- free mailbox channel
|
||||
|
|
@ -117,11 +121,10 @@ void xdna_mailbox_stop_channel(struct mailbox_channel *mailbox_chann);
|
|||
*
|
||||
* @mailbox_chann: Mailbox channel handle
|
||||
* @msg: message struct for message information
|
||||
* @tx_timeout: the timeout value for sending the message in ms.
|
||||
*
|
||||
* Return: If success return 0, otherwise, return error code
|
||||
*/
|
||||
int xdna_mailbox_send_msg(struct mailbox_channel *mailbox_chann,
|
||||
const struct xdna_mailbox_msg *msg, u64 tx_timeout);
|
||||
const struct xdna_mailbox_msg *msg);
|
||||
|
||||
#endif /* _AIE_MAILBOX_ */
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ int xdna_send_msg_wait(struct amdxdna_dev *xdna, struct mailbox_channel *chann,
|
|||
struct xdna_notify *hdl = msg->handle;
|
||||
int ret;
|
||||
|
||||
ret = xdna_mailbox_send_msg(chann, msg, TX_TIMEOUT);
|
||||
ret = xdna_mailbox_send_msg(chann, msg);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Send message failed, ret %d", ret);
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
#ifndef _AMDXDNA_MAILBOX_HELPER_H
|
||||
#define _AMDXDNA_MAILBOX_HELPER_H
|
||||
|
||||
#define TX_TIMEOUT 2000 /* milliseconds */
|
||||
#define RX_TIMEOUT 5000 /* milliseconds */
|
||||
|
||||
struct amdxdna_dev;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/iommu.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "aie.h"
|
||||
#include "amdxdna_cbuf.h"
|
||||
#include "amdxdna_ctx.h"
|
||||
#include "amdxdna_debugfs.h"
|
||||
|
|
@ -151,6 +152,8 @@ static int amdxdna_drm_open(struct drm_device *ddev, struct drm_file *filp)
|
|||
filp->driver_priv = client;
|
||||
client->filp = filp;
|
||||
|
||||
spin_lock_init(&client->io_stats.lock);
|
||||
|
||||
XDNA_DBG(xdna, "pid %d opened", client->pid);
|
||||
return 0;
|
||||
|
||||
|
|
@ -287,6 +290,9 @@ static void amdxdna_show_fdinfo(struct drm_printer *p, struct drm_file *filp)
|
|||
size_t heap_usage, external_usage, internal_usage;
|
||||
char *drv_name = filp->minor->dev->driver->name;
|
||||
|
||||
drm_printf(p, "drm-engine-npu:\t%llu ns\n",
|
||||
amdxdna_io_stats_busy_time_ns(client));
|
||||
|
||||
mutex_lock(&client->mm_lock);
|
||||
|
||||
heap_usage = client->heap_usage;
|
||||
|
|
|
|||
|
|
@ -143,6 +143,13 @@ struct amdxdna_device_id {
|
|||
const struct amdxdna_dev_info *dev_info;
|
||||
};
|
||||
|
||||
struct amdxdna_io_stats {
|
||||
spinlock_t lock; /* protect io stats */
|
||||
int job_depth;
|
||||
u64 start_time;
|
||||
u64 busy_time;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct amdxdna_client - amdxdna client
|
||||
* A per fd data structure for managing context and other user process stuffs.
|
||||
|
|
@ -169,6 +176,8 @@ struct amdxdna_client {
|
|||
size_t heap_usage;
|
||||
size_t total_bo_usage;
|
||||
size_t total_int_bo_usage;
|
||||
|
||||
struct amdxdna_io_stats io_stats;
|
||||
};
|
||||
|
||||
#define amdxdna_for_each_hwctx(client, hwctx_id, entry) \
|
||||
|
|
|
|||
|
|
@ -67,6 +67,48 @@ bool ivpu_force_snoop;
|
|||
module_param_named(force_snoop, ivpu_force_snoop, bool, 0444);
|
||||
MODULE_PARM_DESC(force_snoop, "Force snooping for NPU host memory access");
|
||||
|
||||
static struct pci_device_id ivpu_pci_ids[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_MTL) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_ARL) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_LNL) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PTL) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_WCL) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_NVL) },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, ivpu_pci_ids);
|
||||
|
||||
static int ivpu_ip_gen_init(struct ivpu_device *vdev)
|
||||
{
|
||||
vdev->platform = IVPU_PLATFORM_INVALID;
|
||||
|
||||
switch (ivpu_device_id(vdev)) {
|
||||
case PCI_DEVICE_ID_MTL:
|
||||
case PCI_DEVICE_ID_ARL:
|
||||
vdev->hw_ip_gen = IVPU_HW_IP_37XX;
|
||||
vdev->btrs_gen = IVPU_HW_BTRS_MTL;
|
||||
break;
|
||||
case PCI_DEVICE_ID_LNL:
|
||||
vdev->hw_ip_gen = IVPU_HW_IP_40XX;
|
||||
vdev->btrs_gen = IVPU_HW_BTRS_LNL;
|
||||
break;
|
||||
case PCI_DEVICE_ID_PTL:
|
||||
case PCI_DEVICE_ID_WCL:
|
||||
vdev->hw_ip_gen = IVPU_HW_IP_50XX;
|
||||
vdev->btrs_gen = IVPU_HW_BTRS_LNL;
|
||||
break;
|
||||
case PCI_DEVICE_ID_NVL:
|
||||
vdev->hw_ip_gen = IVPU_HW_IP_60XX;
|
||||
vdev->btrs_gen = IVPU_HW_BTRS_LNL;
|
||||
break;
|
||||
default:
|
||||
ivpu_err(vdev, "Unknown PCI device [%04x:%04x]\n", ivpu_vendor_id(vdev),
|
||||
ivpu_device_id(vdev));
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ivpu_user_limits *ivpu_user_limits_alloc(struct ivpu_device *vdev, uid_t uid)
|
||||
{
|
||||
struct ivpu_user_limits *limits;
|
||||
|
|
@ -248,10 +290,7 @@ static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_f
|
|||
break;
|
||||
case DRM_IVPU_PARAM_FW_API_VERSION:
|
||||
if (args->index < VPU_FW_API_VER_NUM) {
|
||||
struct vpu_firmware_header *fw_hdr;
|
||||
|
||||
fw_hdr = (struct vpu_firmware_header *)vdev->fw->file->data;
|
||||
args->value = fw_hdr->api_version[args->index];
|
||||
args->value = vdev->fw->api_version[args->index];
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
|
@ -481,6 +520,14 @@ int ivpu_boot(struct ivpu_device *vdev)
|
|||
ivpu_fw_boot_params_setup(vdev, ivpu_bo_vaddr(vdev->fw->mem_bp));
|
||||
vdev->fw->last_boot_mode = vdev->fw->next_boot_mode;
|
||||
|
||||
if (!ivpu_fw_is_warm_boot(vdev)) {
|
||||
ret = ivpu_fw_load(vdev);
|
||||
if (ret) {
|
||||
ivpu_err(vdev, "Failed to load the firmware: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ivpu_hw_boot_fw(vdev);
|
||||
if (ret) {
|
||||
ivpu_err(vdev, "Failed to start the firmware: %d\n", ret);
|
||||
|
|
@ -497,6 +544,9 @@ int ivpu_boot(struct ivpu_device *vdev)
|
|||
ivpu_hw_irq_enable(vdev);
|
||||
ivpu_ipc_enable(vdev);
|
||||
|
||||
if (ivpu_test_mode & IVPU_TEST_MODE_FW_TEST)
|
||||
return 0;
|
||||
|
||||
if (!ivpu_fw_is_warm_boot(vdev)) {
|
||||
ret = ivpu_pm_dct_init(vdev);
|
||||
if (ret)
|
||||
|
|
@ -650,6 +700,7 @@ static int ivpu_pci_init(struct ivpu_device *vdev)
|
|||
struct pci_dev *pdev = to_pci_dev(vdev->drm.dev);
|
||||
struct resource *bar0 = &pdev->resource[0];
|
||||
struct resource *bar4 = &pdev->resource[4];
|
||||
int dma_bits;
|
||||
int ret;
|
||||
|
||||
ivpu_dbg(vdev, MISC, "Mapping BAR0 (RegV) %pR\n", bar0);
|
||||
|
|
@ -666,7 +717,12 @@ static int ivpu_pci_init(struct ivpu_device *vdev)
|
|||
return PTR_ERR(vdev->regb);
|
||||
}
|
||||
|
||||
ret = dma_set_mask_and_coherent(vdev->drm.dev, DMA_BIT_MASK(vdev->hw->dma_bits));
|
||||
if (ivpu_hw_ip_gen(vdev) >= IVPU_HW_IP_40XX)
|
||||
dma_bits = 42;
|
||||
else
|
||||
dma_bits = 38;
|
||||
|
||||
ret = dma_set_mask_and_coherent(vdev->drm.dev, DMA_BIT_MASK(dma_bits));
|
||||
if (ret) {
|
||||
ivpu_err(vdev, "Failed to set DMA mask: %d\n", ret);
|
||||
return ret;
|
||||
|
|
@ -714,12 +770,10 @@ static int ivpu_dev_init(struct ivpu_device *vdev)
|
|||
if (!vdev->pm)
|
||||
return -ENOMEM;
|
||||
|
||||
if (ivpu_hw_ip_gen(vdev) >= IVPU_HW_IP_40XX)
|
||||
vdev->hw->dma_bits = 48;
|
||||
else
|
||||
vdev->hw->dma_bits = 38;
|
||||
ret = ivpu_ip_gen_init(vdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
vdev->platform = IVPU_PLATFORM_INVALID;
|
||||
vdev->context_xa_limit.min = IVPU_USER_CONTEXT_MIN_SSID;
|
||||
vdev->context_xa_limit.max = IVPU_USER_CONTEXT_MAX_SSID;
|
||||
atomic64_set(&vdev->unique_id_counter, 0);
|
||||
|
|
@ -852,17 +906,6 @@ static void ivpu_dev_fini(struct ivpu_device *vdev)
|
|||
xa_destroy(&vdev->context_xa);
|
||||
}
|
||||
|
||||
static struct pci_device_id ivpu_pci_ids[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_MTL) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_ARL) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_LNL) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PTL_P) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_WCL) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_NVL) },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, ivpu_pci_ids);
|
||||
|
||||
static int ivpu_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
struct ivpu_device *vdev;
|
||||
|
|
|
|||
|
|
@ -27,21 +27,13 @@
|
|||
#define PCI_DEVICE_ID_MTL 0x7d1d
|
||||
#define PCI_DEVICE_ID_ARL 0xad1d
|
||||
#define PCI_DEVICE_ID_LNL 0x643e
|
||||
#define PCI_DEVICE_ID_PTL_P 0xb03e
|
||||
#define PCI_DEVICE_ID_PTL 0xb03e
|
||||
#define PCI_DEVICE_ID_WCL 0xfd3e
|
||||
#define PCI_DEVICE_ID_NVL 0xd71d
|
||||
|
||||
#define IVPU_HW_IP_37XX 37
|
||||
#define IVPU_HW_IP_40XX 40
|
||||
#define IVPU_HW_IP_50XX 50
|
||||
#define IVPU_HW_IP_60XX 60
|
||||
|
||||
#define IVPU_HW_IP_REV_LNL_B0 4
|
||||
#define IVPU_HW_IP_REV_NVL_A0 0
|
||||
|
||||
#define IVPU_HW_BTRS_MTL 1
|
||||
#define IVPU_HW_BTRS_LNL 2
|
||||
|
||||
#define IVPU_GLOBAL_CONTEXT_MMU_SSID 0
|
||||
/* SSID 1 is used by the VPU to represent reserved context */
|
||||
#define IVPU_RESERVED_CONTEXT_MMU_SSID 1
|
||||
|
|
@ -107,10 +99,21 @@
|
|||
ivpu_dbg(vdev, MISC, "Using WA: " #wa_name "\n"); \
|
||||
} while (0)
|
||||
|
||||
enum vpu_hw_ip {
|
||||
IVPU_HW_IP_37XX = 37,
|
||||
IVPU_HW_IP_40XX = 40,
|
||||
IVPU_HW_IP_50XX = 50,
|
||||
IVPU_HW_IP_60XX = 60,
|
||||
};
|
||||
|
||||
enum vpu_hw_btrs {
|
||||
IVPU_HW_BTRS_MTL = 1,
|
||||
IVPU_HW_BTRS_LNL = 2,
|
||||
};
|
||||
|
||||
struct ivpu_wa_table {
|
||||
bool punit_disabled;
|
||||
bool clear_runtime_mem;
|
||||
bool interrupt_clear_with_0;
|
||||
bool disable_clock_relinquish;
|
||||
bool wp0_during_power_up;
|
||||
bool disable_d0i2;
|
||||
|
|
@ -136,6 +139,8 @@ struct ivpu_device {
|
|||
struct drm_device drm;
|
||||
void __iomem *regb;
|
||||
void __iomem *regv;
|
||||
enum vpu_hw_ip hw_ip_gen;
|
||||
enum vpu_hw_btrs btrs_gen;
|
||||
u32 platform;
|
||||
u32 irq;
|
||||
|
||||
|
|
@ -225,6 +230,7 @@ extern bool ivpu_force_snoop;
|
|||
#define IVPU_TEST_MODE_FW_TEST BIT(0)
|
||||
#define IVPU_TEST_MODE_NULL_HW BIT(1)
|
||||
#define IVPU_TEST_MODE_NULL_SUBMISSION BIT(2)
|
||||
#define IVPU_TEST_MODE_FREQ_CHANGE_ENABLE BIT(3)
|
||||
#define IVPU_TEST_MODE_MIP_DISABLE BIT(6)
|
||||
#define IVPU_TEST_MODE_DISABLE_TIMEOUTS BIT(8)
|
||||
#define IVPU_TEST_MODE_TURBO_ENABLE BIT(9)
|
||||
|
|
@ -247,47 +253,24 @@ static inline u8 ivpu_revision(struct ivpu_device *vdev)
|
|||
return to_pci_dev(vdev->drm.dev)->revision;
|
||||
}
|
||||
|
||||
static inline u16 ivpu_vendor_id(struct ivpu_device *vdev)
|
||||
{
|
||||
return to_pci_dev(vdev->drm.dev)->vendor;
|
||||
}
|
||||
|
||||
static inline u16 ivpu_device_id(struct ivpu_device *vdev)
|
||||
{
|
||||
return to_pci_dev(vdev->drm.dev)->device;
|
||||
}
|
||||
|
||||
static inline int ivpu_hw_ip_gen(struct ivpu_device *vdev)
|
||||
static inline enum vpu_hw_ip ivpu_hw_ip_gen(struct ivpu_device *vdev)
|
||||
{
|
||||
switch (ivpu_device_id(vdev)) {
|
||||
case PCI_DEVICE_ID_MTL:
|
||||
case PCI_DEVICE_ID_ARL:
|
||||
return IVPU_HW_IP_37XX;
|
||||
case PCI_DEVICE_ID_LNL:
|
||||
return IVPU_HW_IP_40XX;
|
||||
case PCI_DEVICE_ID_PTL_P:
|
||||
case PCI_DEVICE_ID_WCL:
|
||||
return IVPU_HW_IP_50XX;
|
||||
case PCI_DEVICE_ID_NVL:
|
||||
return IVPU_HW_IP_60XX;
|
||||
default:
|
||||
dump_stack();
|
||||
ivpu_err(vdev, "Unknown NPU IP generation\n");
|
||||
return 0;
|
||||
}
|
||||
return vdev->hw_ip_gen;
|
||||
}
|
||||
|
||||
static inline int ivpu_hw_btrs_gen(struct ivpu_device *vdev)
|
||||
static inline enum vpu_hw_btrs ivpu_hw_btrs_gen(struct ivpu_device *vdev)
|
||||
{
|
||||
switch (ivpu_device_id(vdev)) {
|
||||
case PCI_DEVICE_ID_MTL:
|
||||
case PCI_DEVICE_ID_ARL:
|
||||
return IVPU_HW_BTRS_MTL;
|
||||
case PCI_DEVICE_ID_LNL:
|
||||
case PCI_DEVICE_ID_PTL_P:
|
||||
case PCI_DEVICE_ID_WCL:
|
||||
case PCI_DEVICE_ID_NVL:
|
||||
return IVPU_HW_BTRS_LNL;
|
||||
default:
|
||||
dump_stack();
|
||||
ivpu_err(vdev, "Unknown buttress generation\n");
|
||||
return 0;
|
||||
}
|
||||
return vdev->btrs_gen;
|
||||
}
|
||||
|
||||
static inline struct ivpu_device *to_ivpu_device(struct drm_device *dev)
|
||||
|
|
|
|||
|
|
@ -28,15 +28,15 @@
|
|||
#define ADDR_TO_L2_CACHE_CFG(addr) ((addr) >> 31)
|
||||
|
||||
/* Check if FW API is compatible with the driver */
|
||||
#define IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, name, min_major) \
|
||||
ivpu_fw_check_api(vdev, fw_hdr, #name, \
|
||||
#define IVPU_FW_CHECK_API_COMPAT(vdev, name, min_major) \
|
||||
ivpu_fw_check_api(vdev, #name, \
|
||||
VPU_##name##_API_VER_INDEX, \
|
||||
VPU_##name##_API_VER_MAJOR, \
|
||||
VPU_##name##_API_VER_MINOR, min_major)
|
||||
|
||||
/* Check if API version is lower that the given version */
|
||||
#define IVPU_FW_CHECK_API_VER_LT(vdev, fw_hdr, name, major, minor) \
|
||||
ivpu_fw_check_api_ver_lt(vdev, fw_hdr, #name, VPU_##name##_API_VER_INDEX, major, minor)
|
||||
#define IVPU_FW_CHECK_API_VER_LT(vdev, name, major, minor) \
|
||||
ivpu_fw_check_api_ver_lt(vdev, #name, VPU_##name##_API_VER_INDEX, major, minor)
|
||||
|
||||
#define IVPU_FOCUS_PRESENT_TIMER_MS 1000
|
||||
|
||||
|
|
@ -93,12 +93,11 @@ static int ivpu_fw_request(struct ivpu_device *vdev)
|
|||
}
|
||||
|
||||
static int
|
||||
ivpu_fw_check_api(struct ivpu_device *vdev, const struct vpu_firmware_header *fw_hdr,
|
||||
const char *str, int index, u16 expected_major, u16 expected_minor,
|
||||
u16 min_major)
|
||||
ivpu_fw_check_api(struct ivpu_device *vdev, const char *str, int index, u16 expected_major,
|
||||
u16 expected_minor, u16 min_major)
|
||||
{
|
||||
u16 major = (u16)(fw_hdr->api_version[index] >> 16);
|
||||
u16 minor = (u16)(fw_hdr->api_version[index]);
|
||||
u16 major = (u16)(vdev->fw->api_version[index] >> 16);
|
||||
u16 minor = (u16)(vdev->fw->api_version[index]);
|
||||
|
||||
if (major < min_major) {
|
||||
ivpu_err(vdev, "Incompatible FW %s API version: %d.%d, required %d.0 or later\n",
|
||||
|
|
@ -116,11 +115,10 @@ ivpu_fw_check_api(struct ivpu_device *vdev, const struct vpu_firmware_header *fw
|
|||
}
|
||||
|
||||
static bool
|
||||
ivpu_fw_check_api_ver_lt(struct ivpu_device *vdev, const struct vpu_firmware_header *fw_hdr,
|
||||
const char *str, int index, u16 major, u16 minor)
|
||||
ivpu_fw_check_api_ver_lt(struct ivpu_device *vdev, const char *str, int index, u16 major, u16 minor)
|
||||
{
|
||||
u16 fw_major = (u16)(fw_hdr->api_version[index] >> 16);
|
||||
u16 fw_minor = (u16)(fw_hdr->api_version[index]);
|
||||
u16 fw_major = (u16)(vdev->fw->api_version[index] >> 16);
|
||||
u16 fw_minor = (u16)(vdev->fw->api_version[index]);
|
||||
|
||||
if (fw_major < major || (fw_major == major && fw_minor < minor))
|
||||
return true;
|
||||
|
|
@ -142,7 +140,7 @@ bool ivpu_is_within_range(u64 addr, size_t size, struct ivpu_addr_range *range)
|
|||
}
|
||||
|
||||
static u32
|
||||
ivpu_fw_sched_mode_select(struct ivpu_device *vdev, const struct vpu_firmware_header *fw_hdr)
|
||||
ivpu_fw_sched_mode_select(struct ivpu_device *vdev)
|
||||
{
|
||||
if (ivpu_hw_ip_gen(vdev) >= IVPU_HW_IP_60XX &&
|
||||
ivpu_sched_mode == VPU_SCHEDULING_MODE_OS) {
|
||||
|
|
@ -153,7 +151,7 @@ ivpu_fw_sched_mode_select(struct ivpu_device *vdev, const struct vpu_firmware_he
|
|||
if (ivpu_sched_mode != IVPU_SCHED_MODE_AUTO)
|
||||
return ivpu_sched_mode;
|
||||
|
||||
if (IVPU_FW_CHECK_API_VER_LT(vdev, fw_hdr, JSM, 3, 24))
|
||||
if (IVPU_FW_CHECK_API_VER_LT(vdev, JSM, 3, 24))
|
||||
return VPU_SCHEDULING_MODE_OS;
|
||||
|
||||
return VPU_SCHEDULING_MODE_HW;
|
||||
|
|
@ -302,9 +300,11 @@ static int ivpu_fw_parse(struct ivpu_device *vdev)
|
|||
|
||||
ivpu_info(vdev, "Firmware: %s, version: %s\n", fw->name, fw->version);
|
||||
|
||||
if (IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, BOOT, 3))
|
||||
memcpy(fw->api_version, fw_hdr->api_version, sizeof(fw->api_version));
|
||||
|
||||
if (IVPU_FW_CHECK_API_COMPAT(vdev, BOOT, 3))
|
||||
return -EINVAL;
|
||||
if (IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, JSM, 3))
|
||||
if (IVPU_FW_CHECK_API_COMPAT(vdev, JSM, 3))
|
||||
return -EINVAL;
|
||||
|
||||
fw->boot_params_addr = boot_params_addr;
|
||||
|
|
@ -324,7 +324,7 @@ static int ivpu_fw_parse(struct ivpu_device *vdev)
|
|||
|
||||
fw->dvfs_mode = 0;
|
||||
|
||||
fw->sched_mode = ivpu_fw_sched_mode_select(vdev, fw_hdr);
|
||||
fw->sched_mode = ivpu_fw_sched_mode_select(vdev);
|
||||
ivpu_info(vdev, "Scheduler mode: %s\n", fw->sched_mode ? "HW" : "OS");
|
||||
|
||||
ivpu_preemption_config_parse(vdev, fw_hdr);
|
||||
|
|
@ -473,8 +473,6 @@ int ivpu_fw_init(struct ivpu_device *vdev)
|
|||
if (ret)
|
||||
goto err_fw_release;
|
||||
|
||||
ivpu_fw_load(vdev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_fw_release:
|
||||
|
|
@ -488,7 +486,7 @@ void ivpu_fw_fini(struct ivpu_device *vdev)
|
|||
ivpu_fw_release(vdev);
|
||||
}
|
||||
|
||||
void ivpu_fw_load(struct ivpu_device *vdev)
|
||||
int ivpu_fw_load(struct ivpu_device *vdev)
|
||||
{
|
||||
struct ivpu_fw_info *fw = vdev->fw;
|
||||
u64 image_end_offset = fw->image_load_offset + fw->image_size;
|
||||
|
|
@ -505,6 +503,7 @@ void ivpu_fw_load(struct ivpu_device *vdev)
|
|||
}
|
||||
|
||||
wmb(); /* Flush WC buffers after writing fw->mem */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ivpu_fw_boot_params_print(struct ivpu_device *vdev, struct vpu_boot_params *boot_params)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ struct ivpu_fw_info {
|
|||
const struct firmware *file;
|
||||
const char *name;
|
||||
char version[FW_VERSION_STR_SIZE];
|
||||
u32 api_version[VPU_FW_API_VER_NUM];
|
||||
struct ivpu_bo *mem_bp;
|
||||
struct ivpu_bo *mem_fw_ver;
|
||||
struct ivpu_bo *mem;
|
||||
|
|
@ -54,7 +55,7 @@ struct ivpu_fw_info {
|
|||
bool ivpu_is_within_range(u64 addr, size_t size, struct ivpu_addr_range *range);
|
||||
int ivpu_fw_init(struct ivpu_device *vdev);
|
||||
void ivpu_fw_fini(struct ivpu_device *vdev);
|
||||
void ivpu_fw_load(struct ivpu_device *vdev);
|
||||
int ivpu_fw_load(struct ivpu_device *vdev);
|
||||
void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params *boot_params);
|
||||
|
||||
static inline bool ivpu_fw_is_warm_boot(struct ivpu_device *vdev)
|
||||
|
|
|
|||
|
|
@ -67,9 +67,6 @@ static void wa_init(struct ivpu_device *vdev)
|
|||
vdev->wa.punit_disabled = false;
|
||||
vdev->wa.clear_runtime_mem = false;
|
||||
|
||||
if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
|
||||
vdev->wa.interrupt_clear_with_0 = ivpu_hw_btrs_irqs_clear_with_0_mtl(vdev);
|
||||
|
||||
if ((ivpu_device_id(vdev) == PCI_DEVICE_ID_LNL &&
|
||||
ivpu_revision(vdev) < IVPU_HW_IP_REV_LNL_B0) ||
|
||||
(ivpu_device_id(vdev) == PCI_DEVICE_ID_NVL &&
|
||||
|
|
@ -90,7 +87,6 @@ static void wa_init(struct ivpu_device *vdev)
|
|||
|
||||
IVPU_PRINT_WA(punit_disabled);
|
||||
IVPU_PRINT_WA(clear_runtime_mem);
|
||||
IVPU_PRINT_WA(interrupt_clear_with_0);
|
||||
IVPU_PRINT_WA(disable_clock_relinquish);
|
||||
IVPU_PRINT_WA(wp0_during_power_up);
|
||||
IVPU_PRINT_WA(disable_d0i2);
|
||||
|
|
@ -98,7 +94,7 @@ static void wa_init(struct ivpu_device *vdev)
|
|||
|
||||
static void timeouts_init(struct ivpu_device *vdev)
|
||||
{
|
||||
if (ivpu_test_mode & IVPU_TEST_MODE_DISABLE_TIMEOUTS) {
|
||||
if (ivpu_test_mode & (IVPU_TEST_MODE_DISABLE_TIMEOUTS | IVPU_TEST_MODE_FW_TEST)) {
|
||||
/* in milliseconds, negative value disables the timeout */
|
||||
vdev->timeout.boot = -1;
|
||||
vdev->timeout.jsm = -1;
|
||||
|
|
@ -378,11 +374,6 @@ void ivpu_hw_profiling_freq_drive(struct ivpu_device *vdev, bool enable)
|
|||
|
||||
void ivpu_irq_handlers_init(struct ivpu_device *vdev)
|
||||
{
|
||||
if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
|
||||
vdev->hw->irq.ip_irq_handler = ivpu_hw_ip_irq_handler_37xx;
|
||||
else
|
||||
vdev->hw->irq.ip_irq_handler = ivpu_hw_ip_irq_handler_40xx;
|
||||
|
||||
if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL)
|
||||
vdev->hw->irq.btrs_irq_handler = ivpu_hw_btrs_irq_handler_mtl;
|
||||
else
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ struct ivpu_addr_range {
|
|||
struct ivpu_hw_info {
|
||||
struct {
|
||||
bool (*btrs_irq_handler)(struct ivpu_device *vdev, int irq);
|
||||
bool (*ip_irq_handler)(struct ivpu_device *vdev, int irq);
|
||||
} irq;
|
||||
struct {
|
||||
struct ivpu_addr_range runtime;
|
||||
|
|
@ -49,9 +48,9 @@ struct ivpu_hw_info {
|
|||
u32 tile_fuse;
|
||||
u32 sku;
|
||||
u16 config;
|
||||
int dma_bits;
|
||||
ktime_t d0i3_entry_host_ts;
|
||||
u64 d0i3_entry_vpu_ts;
|
||||
u32 btrs_irq_mask;
|
||||
atomic_t firewall_irq_counter;
|
||||
};
|
||||
|
||||
|
|
@ -74,11 +73,6 @@ static inline u32 ivpu_hw_btrs_irq_handler(struct ivpu_device *vdev, int irq)
|
|||
return vdev->hw->irq.btrs_irq_handler(vdev, irq);
|
||||
}
|
||||
|
||||
static inline u32 ivpu_hw_ip_irq_handler(struct ivpu_device *vdev, int irq)
|
||||
{
|
||||
return vdev->hw->irq.ip_irq_handler(vdev, irq);
|
||||
}
|
||||
|
||||
static inline u64 ivpu_hw_range_size(const struct ivpu_addr_range *range)
|
||||
{
|
||||
return range->end - range->start;
|
||||
|
|
|
|||
|
|
@ -1,195 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2020-2023 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __IVPU_HW_40XX_REG_H__
|
||||
#define __IVPU_HW_40XX_REG_H__
|
||||
|
||||
#include <linux/bits.h>
|
||||
|
||||
#define VPU_40XX_HOST_SS_CPR_CLK_EN 0x00000080u
|
||||
#define VPU_40XX_HOST_SS_CPR_CLK_EN_TOP_NOC_MASK BIT_MASK(1)
|
||||
#define VPU_40XX_HOST_SS_CPR_CLK_EN_DSS_MAS_MASK BIT_MASK(10)
|
||||
#define VPU_40XX_HOST_SS_CPR_CLK_EN_CSS_MAS_MASK BIT_MASK(11)
|
||||
|
||||
#define VPU_40XX_HOST_SS_CPR_CLK_SET 0x00000084u
|
||||
#define VPU_40XX_HOST_SS_CPR_CLK_SET_TOP_NOC_MASK BIT_MASK(1)
|
||||
#define VPU_40XX_HOST_SS_CPR_CLK_SET_DSS_MAS_MASK BIT_MASK(10)
|
||||
#define VPU_40XX_HOST_SS_CPR_CLK_SET_MSS_MAS_MASK BIT_MASK(11)
|
||||
|
||||
#define VPU_40XX_HOST_SS_CPR_RST_EN 0x00000090u
|
||||
#define VPU_40XX_HOST_SS_CPR_RST_EN_TOP_NOC_MASK BIT_MASK(1)
|
||||
#define VPU_40XX_HOST_SS_CPR_RST_EN_DSS_MAS_MASK BIT_MASK(10)
|
||||
#define VPU_40XX_HOST_SS_CPR_RST_EN_CSS_MAS_MASK BIT_MASK(11)
|
||||
|
||||
#define VPU_40XX_HOST_SS_CPR_RST_SET 0x00000094u
|
||||
#define VPU_40XX_HOST_SS_CPR_RST_SET_TOP_NOC_MASK BIT_MASK(1)
|
||||
#define VPU_40XX_HOST_SS_CPR_RST_SET_DSS_MAS_MASK BIT_MASK(10)
|
||||
#define VPU_40XX_HOST_SS_CPR_RST_SET_MSS_MAS_MASK BIT_MASK(11)
|
||||
|
||||
#define VPU_40XX_HOST_SS_CPR_RST_CLR 0x00000098u
|
||||
#define VPU_40XX_HOST_SS_CPR_RST_CLR_TOP_NOC_MASK BIT_MASK(1)
|
||||
#define VPU_40XX_HOST_SS_CPR_RST_CLR_DSS_MAS_MASK BIT_MASK(10)
|
||||
#define VPU_40XX_HOST_SS_CPR_RST_CLR_MSS_MAS_MASK BIT_MASK(11)
|
||||
|
||||
#define VPU_40XX_HOST_SS_HW_VERSION 0x00000108u
|
||||
#define VPU_40XX_HOST_SS_HW_VERSION_SOC_REVISION_MASK GENMASK(7, 0)
|
||||
#define VPU_40XX_HOST_SS_HW_VERSION_SOC_NUMBER_MASK GENMASK(15, 8)
|
||||
#define VPU_40XX_HOST_SS_HW_VERSION_VPU_GENERATION_MASK GENMASK(23, 16)
|
||||
|
||||
#define VPU_40XX_HOST_SS_SW_VERSION 0x0000010cu
|
||||
|
||||
#define VPU_40XX_HOST_SS_GEN_CTRL 0x00000118u
|
||||
#define VPU_40XX_HOST_SS_GEN_CTRL_PS_MASK GENMASK(31, 29)
|
||||
|
||||
#define VPU_40XX_HOST_SS_NOC_QREQN 0x00000154u
|
||||
#define VPU_40XX_HOST_SS_NOC_QREQN_TOP_SOCMMIO_MASK BIT_MASK(0)
|
||||
|
||||
#define VPU_40XX_HOST_SS_NOC_QACCEPTN 0x00000158u
|
||||
#define VPU_40XX_HOST_SS_NOC_QACCEPTN_TOP_SOCMMIO_MASK BIT_MASK(0)
|
||||
|
||||
#define VPU_40XX_HOST_SS_NOC_QDENY 0x0000015cu
|
||||
#define VPU_40XX_HOST_SS_NOC_QDENY_TOP_SOCMMIO_MASK BIT_MASK(0)
|
||||
|
||||
#define VPU_40XX_TOP_NOC_QREQN 0x00000160u
|
||||
#define VPU_40XX_TOP_NOC_QREQN_CPU_CTRL_MASK BIT_MASK(0)
|
||||
#define VPU_40XX_TOP_NOC_QREQN_HOSTIF_L2CACHE_MASK BIT_MASK(2)
|
||||
|
||||
#define VPU_40XX_TOP_NOC_QACCEPTN 0x00000164u
|
||||
#define VPU_40XX_TOP_NOC_QACCEPTN_CPU_CTRL_MASK BIT_MASK(0)
|
||||
#define VPU_40XX_TOP_NOC_QACCEPTN_HOSTIF_L2CACHE_MASK BIT_MASK(2)
|
||||
|
||||
#define VPU_40XX_TOP_NOC_QDENY 0x00000168u
|
||||
#define VPU_40XX_TOP_NOC_QDENY_CPU_CTRL_MASK BIT_MASK(0)
|
||||
#define VPU_40XX_TOP_NOC_QDENY_HOSTIF_L2CACHE_MASK BIT_MASK(2)
|
||||
|
||||
#define VPU_40XX_HOST_SS_FW_SOC_IRQ_EN 0x00000170u
|
||||
#define VPU_40XX_HOST_SS_FW_SOC_IRQ_EN_CSS_ROM_CMX_MASK BIT_MASK(0)
|
||||
#define VPU_40XX_HOST_SS_FW_SOC_IRQ_EN_CSS_DBG_MASK BIT_MASK(1)
|
||||
#define VPU_40XX_HOST_SS_FW_SOC_IRQ_EN_CSS_CTRL_MASK BIT_MASK(2)
|
||||
#define VPU_40XX_HOST_SS_FW_SOC_IRQ_EN_DEC400_MASK BIT_MASK(3)
|
||||
#define VPU_40XX_HOST_SS_FW_SOC_IRQ_EN_MSS_NCE_MASK BIT_MASK(4)
|
||||
#define VPU_40XX_HOST_SS_FW_SOC_IRQ_EN_MSS_MBI_MASK BIT_MASK(5)
|
||||
#define VPU_40XX_HOST_SS_FW_SOC_IRQ_EN_MSS_MBI_CMX_MASK BIT_MASK(6)
|
||||
|
||||
#define VPU_40XX_HOST_SS_ICB_STATUS_0 0x00010210u
|
||||
#define VPU_40XX_HOST_SS_ICB_STATUS_0_TIMER_0_INT_MASK BIT_MASK(0)
|
||||
#define VPU_40XX_HOST_SS_ICB_STATUS_0_TIMER_1_INT_MASK BIT_MASK(1)
|
||||
#define VPU_40XX_HOST_SS_ICB_STATUS_0_TIMER_2_INT_MASK BIT_MASK(2)
|
||||
#define VPU_40XX_HOST_SS_ICB_STATUS_0_TIMER_3_INT_MASK BIT_MASK(3)
|
||||
#define VPU_40XX_HOST_SS_ICB_STATUS_0_HOST_IPC_FIFO_INT_MASK BIT_MASK(4)
|
||||
#define VPU_40XX_HOST_SS_ICB_STATUS_0_MMU_IRQ_0_INT_MASK BIT_MASK(5)
|
||||
#define VPU_40XX_HOST_SS_ICB_STATUS_0_MMU_IRQ_1_INT_MASK BIT_MASK(6)
|
||||
#define VPU_40XX_HOST_SS_ICB_STATUS_0_MMU_IRQ_2_INT_MASK BIT_MASK(7)
|
||||
#define VPU_40XX_HOST_SS_ICB_STATUS_0_NOC_FIREWALL_INT_MASK BIT_MASK(8)
|
||||
#define VPU_40XX_HOST_SS_ICB_STATUS_0_CPU_INT_REDIRECT_0_INT_MASK BIT_MASK(30)
|
||||
#define VPU_40XX_HOST_SS_ICB_STATUS_0_CPU_INT_REDIRECT_1_INT_MASK BIT_MASK(31)
|
||||
|
||||
#define VPU_40XX_HOST_SS_ICB_STATUS_1 0x00010214u
|
||||
#define VPU_40XX_HOST_SS_ICB_STATUS_1_CPU_INT_REDIRECT_2_INT_MASK BIT_MASK(0)
|
||||
#define VPU_40XX_HOST_SS_ICB_STATUS_1_CPU_INT_REDIRECT_3_INT_MASK BIT_MASK(1)
|
||||
#define VPU_40XX_HOST_SS_ICB_STATUS_1_CPU_INT_REDIRECT_4_INT_MASK BIT_MASK(2)
|
||||
|
||||
#define VPU_40XX_HOST_SS_ICB_CLEAR_0 0x00010220u
|
||||
#define VPU_40XX_HOST_SS_ICB_CLEAR_1 0x00010224u
|
||||
#define VPU_40XX_HOST_SS_ICB_ENABLE_0 0x00010240u
|
||||
#define VPU_40XX_HOST_SS_ICB_ENABLE_1 0x00010244u
|
||||
|
||||
#define VPU_40XX_HOST_SS_TIM_IPC_FIFO_ATM 0x000200f4u
|
||||
|
||||
#define VPU_40XX_HOST_SS_TIM_IPC_FIFO_STAT 0x000200fcu
|
||||
#define VPU_40XX_HOST_SS_TIM_IPC_FIFO_STAT_FILL_LEVEL_MASK GENMASK(23, 16)
|
||||
|
||||
#define VPU_40XX_HOST_SS_AON_PWR_ISO_EN0 0x00030020u
|
||||
#define VPU_40XX_HOST_SS_AON_PWR_ISO_EN0_CSS_CPU_MASK BIT_MASK(3)
|
||||
|
||||
#define VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0 0x00030024u
|
||||
#define VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0_CSS_CPU_MASK BIT_MASK(3)
|
||||
|
||||
#define VPU_40XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0 0x00030028u
|
||||
#define VPU_40XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0_CSS_CPU_MASK BIT_MASK(3)
|
||||
|
||||
#define VPU_40XX_HOST_SS_AON_PWR_ISLAND_STATUS0 0x0003002cu
|
||||
#define VPU_40XX_HOST_SS_AON_PWR_ISLAND_STATUS0_CSS_CPU_MASK BIT_MASK(3)
|
||||
|
||||
#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY 0x00030068u
|
||||
#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY_POST_DLY_MASK GENMASK(7, 0)
|
||||
#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY_POST1_DLY_MASK GENMASK(15, 8)
|
||||
#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY_POST2_DLY_MASK GENMASK(23, 16)
|
||||
|
||||
#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY 0x0003006cu
|
||||
#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY_STATUS_DLY_MASK GENMASK(7, 0)
|
||||
|
||||
#define VPU_40XX_HOST_SS_AON_IDLE_GEN 0x00030200u
|
||||
#define VPU_40XX_HOST_SS_AON_IDLE_GEN_EN_MASK BIT_MASK(0)
|
||||
#define VPU_40XX_HOST_SS_AON_IDLE_GEN_HW_PG_EN_MASK BIT_MASK(1)
|
||||
|
||||
#define VPU_40XX_HOST_SS_AON_DPU_ACTIVE 0x00030204u
|
||||
#define VPU_40XX_HOST_SS_AON_DPU_ACTIVE_DPU_ACTIVE_MASK BIT_MASK(0)
|
||||
|
||||
#define VPU_50XX_HOST_SS_AON_FABRIC_REQ_OVERRIDE 0x00030210u
|
||||
#define VPU_50XX_HOST_SS_AON_FABRIC_REQ_OVERRIDE_REQ_OVERRIDE_MASK BIT_MASK(0)
|
||||
|
||||
#define VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO 0x00040040u
|
||||
#define VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO_DONE_MASK BIT_MASK(0)
|
||||
#define VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO_IOSF_RS_ID_MASK GENMASK(2, 1)
|
||||
#define VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO_IMAGE_LOCATION_MASK GENMASK(31, 3)
|
||||
|
||||
#define VPU_40XX_HOST_SS_WORKPOINT_CONFIG_MIRROR 0x00082020u
|
||||
#define VPU_40XX_HOST_SS_WORKPOINT_CONFIG_MIRROR_FINAL_PLL_FREQ_MASK GENMASK(15, 0)
|
||||
#define VPU_40XX_HOST_SS_WORKPOINT_CONFIG_MIRROR_CONFIG_ID_MASK GENMASK(31, 16)
|
||||
|
||||
#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES 0x00360000u
|
||||
#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES_CACHE_OVERRIDE_EN_MASK BIT_MASK(0)
|
||||
#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES_AWCACHE_OVERRIDE_MASK BIT_MASK(1)
|
||||
#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES_ARCACHE_OVERRIDE_MASK BIT_MASK(2)
|
||||
#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES_SNOOP_OVERRIDE_EN_MASK BIT_MASK(3)
|
||||
#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES_AW_SNOOP_OVERRIDE_MASK BIT_MASK(4)
|
||||
#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES_AR_SNOOP_OVERRIDE_MASK BIT_MASK(5)
|
||||
#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES_PTW_AW_CONTEXT_FLAG_MASK GENMASK(10, 6)
|
||||
#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES_PTW_AR_CONTEXT_FLAG_MASK GENMASK(15, 11)
|
||||
|
||||
#define VPU_40XX_HOST_IF_TBU_MMUSSIDV 0x00360004u
|
||||
#define VPU_40XX_HOST_IF_TBU_MMUSSIDV_TBU0_AWMMUSSIDV_MASK BIT_MASK(0)
|
||||
#define VPU_40XX_HOST_IF_TBU_MMUSSIDV_TBU0_ARMMUSSIDV_MASK BIT_MASK(1)
|
||||
#define VPU_40XX_HOST_IF_TBU_MMUSSIDV_TBU1_AWMMUSSIDV_MASK BIT_MASK(2)
|
||||
#define VPU_40XX_HOST_IF_TBU_MMUSSIDV_TBU1_ARMMUSSIDV_MASK BIT_MASK(3)
|
||||
#define VPU_40XX_HOST_IF_TBU_MMUSSIDV_TBU2_AWMMUSSIDV_MASK BIT_MASK(4)
|
||||
#define VPU_40XX_HOST_IF_TBU_MMUSSIDV_TBU2_ARMMUSSIDV_MASK BIT_MASK(5)
|
||||
#define VPU_40XX_HOST_IF_TBU_MMUSSIDV_TBU3_AWMMUSSIDV_MASK BIT_MASK(6)
|
||||
#define VPU_40XX_HOST_IF_TBU_MMUSSIDV_TBU3_ARMMUSSIDV_MASK BIT_MASK(7)
|
||||
#define VPU_40XX_HOST_IF_TBU_MMUSSIDV_TBU4_AWMMUSSIDV_MASK BIT_MASK(8)
|
||||
#define VPU_40XX_HOST_IF_TBU_MMUSSIDV_TBU4_ARMMUSSIDV_MASK BIT_MASK(9)
|
||||
|
||||
#define VPU_40XX_CPU_SS_DSU_LEON_RT_BASE 0x04000000u
|
||||
#define VPU_40XX_CPU_SS_DSU_LEON_RT_DSU_CTRL 0x04000000u
|
||||
#define VPU_40XX_CPU_SS_DSU_LEON_RT_PC_REG 0x04400010u
|
||||
#define VPU_40XX_CPU_SS_DSU_LEON_RT_NPC_REG 0x04400014u
|
||||
#define VPU_40XX_CPU_SS_DSU_LEON_RT_DSU_TRAP_REG 0x04400020u
|
||||
|
||||
#define VPU_40XX_CPU_SS_TIM_WATCHDOG 0x0102009cu
|
||||
#define VPU_40XX_CPU_SS_TIM_WDOG_EN 0x010200a4u
|
||||
#define VPU_40XX_CPU_SS_TIM_SAFE 0x010200a8u
|
||||
|
||||
#define VPU_40XX_CPU_SS_TIM_GEN_CONFIG 0x01021008u
|
||||
#define VPU_40XX_CPU_SS_TIM_GEN_CONFIG_WDOG_TO_INT_CLR_MASK BIT_MASK(9)
|
||||
|
||||
#define VPU_40XX_CPU_SS_CPR_NOC_QREQN 0x01010030u
|
||||
#define VPU_40XX_CPU_SS_CPR_NOC_QREQN_TOP_MMIO_MASK BIT_MASK(0)
|
||||
|
||||
#define VPU_40XX_CPU_SS_CPR_NOC_QACCEPTN 0x01010034u
|
||||
#define VPU_40XX_CPU_SS_CPR_NOC_QACCEPTN_TOP_MMIO_MASK BIT_MASK(0)
|
||||
|
||||
#define VPU_40XX_CPU_SS_CPR_NOC_QDENY 0x01010038u
|
||||
#define VPU_40XX_CPU_SS_CPR_NOC_QDENY_TOP_MMIO_MASK BIT_MASK(0)
|
||||
|
||||
#define VPU_40XX_CPU_SS_TIM_IPC_FIFO 0x010200f0u
|
||||
#define VPU_40XX_CPU_SS_TIM_PERF_EXT_FREE_CNT 0x01029008u
|
||||
|
||||
#define VPU_40XX_CPU_SS_DOORBELL_0 0x01300000u
|
||||
#define VPU_40XX_CPU_SS_DOORBELL_0_SET_MASK BIT_MASK(0)
|
||||
|
||||
#define VPU_40XX_CPU_SS_DOORBELL_1 0x01301000u
|
||||
|
||||
#endif /* __IVPU_HW_40XX_REG_H__ */
|
||||
|
|
@ -8,8 +8,7 @@
|
|||
#include "ivpu_drv.h"
|
||||
#include "ivpu_hw.h"
|
||||
#include "ivpu_hw_btrs.h"
|
||||
#include "ivpu_hw_btrs_lnl_reg.h"
|
||||
#include "ivpu_hw_btrs_mtl_reg.h"
|
||||
#include "ivpu_hw_btrs_reg.h"
|
||||
#include "ivpu_hw_reg_io.h"
|
||||
#include "ivpu_jsm_msg.h"
|
||||
#include "ivpu_pm.h"
|
||||
|
|
@ -24,9 +23,6 @@
|
|||
(REG_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, IMR1_ERR)) | \
|
||||
(REG_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, SURV_ERR)))
|
||||
|
||||
#define BTRS_MTL_ALL_IRQ_MASK (BTRS_MTL_IRQ_MASK | (REG_FLD(VPU_HW_BTRS_MTL_INTERRUPT_STAT, \
|
||||
FREQ_CHANGE)))
|
||||
|
||||
#define BTRS_IRQ_DISABLE_MASK ((u32)-1)
|
||||
|
||||
#define BTRS_LNL_ALL_IRQ_MASK ((u32)-1)
|
||||
|
|
@ -49,9 +45,6 @@
|
|||
#define BTRS_MTL_TILE_FUSE_ENABLE_BOTH 0x0
|
||||
#define BTRS_MTL_TILE_SKU_BOTH 0x3630
|
||||
|
||||
#define BTRS_LNL_TILE_MAX_NUM 6
|
||||
#define BTRS_LNL_TILE_MAX_MASK 0x3f
|
||||
|
||||
#define WEIGHTS_DEFAULT 0xf711f711u
|
||||
#define WEIGHTS_ATS_DEFAULT 0x0000f711u
|
||||
|
||||
|
|
@ -59,18 +52,6 @@
|
|||
#define DCT_ENABLE 0x1
|
||||
#define DCT_DISABLE 0x0
|
||||
|
||||
int ivpu_hw_btrs_irqs_clear_with_0_mtl(struct ivpu_device *vdev)
|
||||
{
|
||||
REGB_WR32(VPU_HW_BTRS_MTL_INTERRUPT_STAT, BTRS_MTL_ALL_IRQ_MASK);
|
||||
if (REGB_RD32(VPU_HW_BTRS_MTL_INTERRUPT_STAT) == BTRS_MTL_ALL_IRQ_MASK) {
|
||||
/* Writing 1s does not clear the interrupt status register */
|
||||
REGB_WR32(VPU_HW_BTRS_MTL_INTERRUPT_STAT, 0x0);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void freq_ratios_init_mtl(struct ivpu_device *vdev)
|
||||
{
|
||||
struct ivpu_hw_info *hw = vdev->hw;
|
||||
|
|
@ -115,13 +96,9 @@ void ivpu_hw_btrs_freq_ratios_init(struct ivpu_device *vdev)
|
|||
|
||||
static bool tile_disable_check(u32 config)
|
||||
{
|
||||
/* Allowed values: 0 or one bit from range 0-5 (6 tiles) */
|
||||
if (config == 0)
|
||||
return true;
|
||||
|
||||
if (config > BIT(BTRS_LNL_TILE_MAX_NUM - 1))
|
||||
return false;
|
||||
|
||||
if ((config & (config - 1)) == 0)
|
||||
return true;
|
||||
|
||||
|
|
@ -156,6 +133,11 @@ static int info_init_mtl(struct ivpu_device *vdev)
|
|||
hw->tile_fuse = BTRS_MTL_TILE_FUSE_ENABLE_BOTH;
|
||||
hw->sku = BTRS_MTL_TILE_SKU_BOTH;
|
||||
hw->config = WP_CONFIG(MTL_CONFIG_2_TILE, MTL_PLL_RATIO_4_3);
|
||||
hw->btrs_irq_mask = BTRS_MTL_IRQ_MASK;
|
||||
|
||||
if (ivpu_test_mode & IVPU_TEST_MODE_FREQ_CHANGE_ENABLE)
|
||||
hw->btrs_irq_mask = REG_SET_FLD(VPU_HW_BTRS_MTL_INTERRUPT_STAT, FREQ_CHANGE,
|
||||
hw->btrs_irq_mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -172,6 +154,11 @@ static int info_init_lnl(struct ivpu_device *vdev)
|
|||
|
||||
hw->tile_fuse = tile_fuse_config;
|
||||
hw->pll.profiling_freq = PLL_PROFILING_FREQ_DEFAULT;
|
||||
hw->btrs_irq_mask = BTRS_LNL_IRQ_MASK;
|
||||
|
||||
if (ivpu_test_mode & IVPU_TEST_MODE_FREQ_CHANGE_ENABLE)
|
||||
hw->btrs_irq_mask = REG_SET_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, FREQ_CHANGE,
|
||||
hw->btrs_irq_mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -698,7 +685,7 @@ int ivpu_hw_btrs_cfg_freq_init(struct ivpu_device *vdev)
|
|||
/* Handler for IRQs from Buttress core (irqB) */
|
||||
bool ivpu_hw_btrs_irq_handler_mtl(struct ivpu_device *vdev, int irq)
|
||||
{
|
||||
u32 status = REGB_RD32(VPU_HW_BTRS_MTL_INTERRUPT_STAT) & BTRS_MTL_IRQ_MASK;
|
||||
u32 status = REGB_RD32(VPU_HW_BTRS_MTL_INTERRUPT_STAT) & vdev->hw->btrs_irq_mask;
|
||||
bool schedule_recovery = false;
|
||||
|
||||
if (!status)
|
||||
|
|
@ -729,14 +716,7 @@ bool ivpu_hw_btrs_irq_handler_mtl(struct ivpu_device *vdev, int irq)
|
|||
}
|
||||
|
||||
/* This must be done after interrupts are cleared at the source. */
|
||||
if (IVPU_WA(interrupt_clear_with_0))
|
||||
/*
|
||||
* Writing 1 triggers an interrupt, so we can't perform read update write.
|
||||
* Clear local interrupt status by writing 0 to all bits.
|
||||
*/
|
||||
REGB_WR32(VPU_HW_BTRS_MTL_INTERRUPT_STAT, 0x0);
|
||||
else
|
||||
REGB_WR32(VPU_HW_BTRS_MTL_INTERRUPT_STAT, status);
|
||||
REGB_WR32(VPU_HW_BTRS_MTL_INTERRUPT_STAT, status);
|
||||
|
||||
if (schedule_recovery)
|
||||
ivpu_pm_trigger_recovery(vdev, "Buttress IRQ");
|
||||
|
|
@ -747,7 +727,7 @@ bool ivpu_hw_btrs_irq_handler_mtl(struct ivpu_device *vdev, int irq)
|
|||
/* Handler for IRQs from Buttress core (irqB) */
|
||||
bool ivpu_hw_btrs_irq_handler_lnl(struct ivpu_device *vdev, int irq)
|
||||
{
|
||||
u32 status = REGB_RD32(VPU_HW_BTRS_LNL_INTERRUPT_STAT) & BTRS_LNL_IRQ_MASK;
|
||||
u32 status = REGB_RD32(VPU_HW_BTRS_LNL_INTERRUPT_STAT) & vdev->hw->btrs_irq_mask;
|
||||
bool schedule_recovery = false;
|
||||
|
||||
if (!status)
|
||||
|
|
@ -889,10 +869,10 @@ void ivpu_hw_btrs_global_int_enable(struct ivpu_device *vdev)
|
|||
void ivpu_hw_btrs_irq_enable(struct ivpu_device *vdev)
|
||||
{
|
||||
if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL) {
|
||||
REGB_WR32(VPU_HW_BTRS_MTL_LOCAL_INT_MASK, (u32)(~BTRS_MTL_IRQ_MASK));
|
||||
REGB_WR32(VPU_HW_BTRS_MTL_LOCAL_INT_MASK, (u32)(~vdev->hw->btrs_irq_mask));
|
||||
REGB_WR32(VPU_HW_BTRS_MTL_GLOBAL_INT_MASK, 0x0);
|
||||
} else {
|
||||
REGB_WR32(VPU_HW_BTRS_LNL_LOCAL_INT_MASK, (u32)(~BTRS_LNL_IRQ_MASK));
|
||||
REGB_WR32(VPU_HW_BTRS_LNL_LOCAL_INT_MASK, (u32)(~vdev->hw->btrs_irq_mask));
|
||||
REGB_WR32(VPU_HW_BTRS_LNL_GLOBAL_INT_MASK, 0x0);
|
||||
}
|
||||
}
|
||||
|
|
@ -910,7 +890,7 @@ void ivpu_hw_btrs_irq_disable(struct ivpu_device *vdev)
|
|||
|
||||
static void diagnose_failure_mtl(struct ivpu_device *vdev)
|
||||
{
|
||||
u32 reg = REGB_RD32(VPU_HW_BTRS_MTL_INTERRUPT_STAT) & BTRS_MTL_IRQ_MASK;
|
||||
u32 reg = REGB_RD32(VPU_HW_BTRS_MTL_INTERRUPT_STAT) & vdev->hw->btrs_irq_mask;
|
||||
|
||||
if (REG_TEST_FLD(VPU_HW_BTRS_MTL_INTERRUPT_STAT, ATS_ERR, reg))
|
||||
ivpu_err(vdev, "ATS_ERR irq 0x%016llx", REGB_RD64(VPU_HW_BTRS_MTL_ATS_ERR_LOG_0));
|
||||
|
|
@ -927,7 +907,7 @@ static void diagnose_failure_mtl(struct ivpu_device *vdev)
|
|||
|
||||
static void diagnose_failure_lnl(struct ivpu_device *vdev)
|
||||
{
|
||||
u32 reg = REGB_RD32(VPU_HW_BTRS_LNL_INTERRUPT_STAT) & BTRS_LNL_IRQ_MASK;
|
||||
u32 reg = REGB_RD32(VPU_HW_BTRS_LNL_INTERRUPT_STAT) & vdev->hw->btrs_irq_mask;
|
||||
|
||||
if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, ATS_ERR, reg)) {
|
||||
ivpu_err(vdev, "ATS_ERR_LOG1 0x%08x ATS_ERR_LOG2 0x%08x\n",
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@
|
|||
#define __IVPU_HW_BTRS_H__
|
||||
|
||||
#include "ivpu_drv.h"
|
||||
#include "ivpu_hw_37xx_reg.h"
|
||||
#include "ivpu_hw_40xx_reg.h"
|
||||
#include "ivpu_hw_reg_io.h"
|
||||
|
||||
#define PLL_PROFILING_FREQ_DEFAULT 38400000
|
||||
|
|
@ -19,7 +17,6 @@
|
|||
|
||||
int ivpu_hw_btrs_info_init(struct ivpu_device *vdev);
|
||||
void ivpu_hw_btrs_freq_ratios_init(struct ivpu_device *vdev);
|
||||
int ivpu_hw_btrs_irqs_clear_with_0_mtl(struct ivpu_device *vdev);
|
||||
int ivpu_hw_btrs_wp_drive(struct ivpu_device *vdev, bool enable);
|
||||
int ivpu_hw_btrs_wait_for_clock_res_own_ack(struct ivpu_device *vdev);
|
||||
int ivpu_hw_btrs_d0i3_enable(struct ivpu_device *vdev);
|
||||
|
|
|
|||
|
|
@ -1,83 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2020-2023 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __IVPU_HW_BTRS_MTL_REG_H__
|
||||
#define __IVPU_HW_BTRS_MTL_REG_H__
|
||||
|
||||
#include <linux/bits.h>
|
||||
|
||||
#define VPU_HW_BTRS_MTL_INTERRUPT_TYPE 0x00000000u
|
||||
|
||||
#define VPU_HW_BTRS_MTL_INTERRUPT_STAT 0x00000004u
|
||||
#define VPU_HW_BTRS_MTL_INTERRUPT_STAT_FREQ_CHANGE_MASK BIT_MASK(0)
|
||||
#define VPU_HW_BTRS_MTL_INTERRUPT_STAT_ATS_ERR_MASK BIT_MASK(1)
|
||||
#define VPU_HW_BTRS_MTL_INTERRUPT_STAT_UFI_ERR_MASK BIT_MASK(2)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD0 0x00000008u
|
||||
#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD0_MIN_RATIO_MASK GENMASK(15, 0)
|
||||
#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD0_MAX_RATIO_MASK GENMASK(31, 16)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD1 0x0000000cu
|
||||
#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD1_TARGET_RATIO_MASK GENMASK(15, 0)
|
||||
#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD1_EPP_MASK GENMASK(31, 16)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD2 0x00000010u
|
||||
#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD2_CONFIG_MASK GENMASK(15, 0)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_WP_REQ_CMD 0x00000014u
|
||||
#define VPU_HW_BTRS_MTL_WP_REQ_CMD_SEND_MASK BIT_MASK(0)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_WP_DOWNLOAD 0x00000018u
|
||||
#define VPU_HW_BTRS_MTL_WP_DOWNLOAD_TARGET_RATIO_MASK GENMASK(15, 0)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_CURRENT_PLL 0x0000001cu
|
||||
#define VPU_HW_BTRS_MTL_CURRENT_PLL_RATIO_MASK GENMASK(15, 0)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_PLL_ENABLE 0x00000020u
|
||||
|
||||
#define VPU_HW_BTRS_MTL_FMIN_FUSE 0x00000024u
|
||||
#define VPU_HW_BTRS_MTL_FMIN_FUSE_MIN_RATIO_MASK GENMASK(7, 0)
|
||||
#define VPU_HW_BTRS_MTL_FMIN_FUSE_PN_RATIO_MASK GENMASK(15, 8)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_FMAX_FUSE 0x00000028u
|
||||
#define VPU_HW_BTRS_MTL_FMAX_FUSE_MAX_RATIO_MASK GENMASK(7, 0)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_TILE_FUSE 0x0000002cu
|
||||
#define VPU_HW_BTRS_MTL_TILE_FUSE_VALID_MASK BIT_MASK(0)
|
||||
#define VPU_HW_BTRS_MTL_TILE_FUSE_SKU_MASK GENMASK(3, 2)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_LOCAL_INT_MASK 0x00000030u
|
||||
#define VPU_HW_BTRS_MTL_GLOBAL_INT_MASK 0x00000034u
|
||||
|
||||
#define VPU_HW_BTRS_MTL_PLL_STATUS 0x00000040u
|
||||
#define VPU_HW_BTRS_MTL_PLL_STATUS_LOCK_MASK BIT_MASK(1)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_VPU_STATUS 0x00000044u
|
||||
#define VPU_HW_BTRS_MTL_VPU_STATUS_READY_MASK BIT_MASK(0)
|
||||
#define VPU_HW_BTRS_MTL_VPU_STATUS_IDLE_MASK BIT_MASK(1)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_VPU_D0I3_CONTROL 0x00000060u
|
||||
#define VPU_HW_BTRS_MTL_VPU_D0I3_CONTROL_INPROGRESS_MASK BIT_MASK(0)
|
||||
#define VPU_HW_BTRS_MTL_VPU_D0I3_CONTROL_I3_MASK BIT_MASK(2)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_VPU_IP_RESET 0x00000050u
|
||||
#define VPU_HW_BTRS_MTL_VPU_IP_RESET_TRIGGER_MASK BIT_MASK(0)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_VPU_TELEMETRY_OFFSET 0x00000080u
|
||||
#define VPU_HW_BTRS_MTL_VPU_TELEMETRY_SIZE 0x00000084u
|
||||
#define VPU_HW_BTRS_MTL_VPU_TELEMETRY_ENABLE 0x00000088u
|
||||
|
||||
#define VPU_HW_BTRS_MTL_ATS_ERR_LOG_0 0x000000a0u
|
||||
#define VPU_HW_BTRS_MTL_ATS_ERR_LOG_1 0x000000a4u
|
||||
#define VPU_HW_BTRS_MTL_ATS_ERR_CLEAR 0x000000a8u
|
||||
|
||||
#define VPU_HW_BTRS_MTL_UFI_ERR_LOG 0x000000b0u
|
||||
#define VPU_HW_BTRS_MTL_UFI_ERR_LOG_CQ_ID_MASK GENMASK(11, 0)
|
||||
#define VPU_HW_BTRS_MTL_UFI_ERR_LOG_AXI_ID_MASK GENMASK(19, 12)
|
||||
#define VPU_HW_BTRS_MTL_UFI_ERR_LOG_OPCODE_MASK GENMASK(24, 20)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_UFI_ERR_CLEAR 0x000000b4u
|
||||
|
||||
#endif /* __IVPU_HW_BTRS_MTL_REG_H__ */
|
||||
|
|
@ -1,13 +1,85 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2020-2024 Intel Corporation
|
||||
* Copyright (C) 2020-2026 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __IVPU_HW_BTRS_LNL_REG_H__
|
||||
#define __IVPU_HW_BTRS_LNL_REG_H__
|
||||
#ifndef __IVPU_HW_BTRS_REG_H__
|
||||
#define __IVPU_HW_BTRS_REG_H__
|
||||
|
||||
#include <linux/bits.h>
|
||||
|
||||
#define VPU_HW_BTRS_MTL_INTERRUPT_TYPE 0x00000000u
|
||||
|
||||
#define VPU_HW_BTRS_MTL_INTERRUPT_STAT 0x00000004u
|
||||
#define VPU_HW_BTRS_MTL_INTERRUPT_STAT_FREQ_CHANGE_MASK BIT_MASK(0)
|
||||
#define VPU_HW_BTRS_MTL_INTERRUPT_STAT_ATS_ERR_MASK BIT_MASK(1)
|
||||
#define VPU_HW_BTRS_MTL_INTERRUPT_STAT_UFI_ERR_MASK BIT_MASK(2)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD0 0x00000008u
|
||||
#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD0_MIN_RATIO_MASK GENMASK(15, 0)
|
||||
#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD0_MAX_RATIO_MASK GENMASK(31, 16)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD1 0x0000000cu
|
||||
#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD1_TARGET_RATIO_MASK GENMASK(15, 0)
|
||||
#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD1_EPP_MASK GENMASK(31, 16)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD2 0x00000010u
|
||||
#define VPU_HW_BTRS_MTL_WP_REQ_PAYLOAD2_CONFIG_MASK GENMASK(15, 0)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_WP_REQ_CMD 0x00000014u
|
||||
#define VPU_HW_BTRS_MTL_WP_REQ_CMD_SEND_MASK BIT_MASK(0)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_WP_DOWNLOAD 0x00000018u
|
||||
#define VPU_HW_BTRS_MTL_WP_DOWNLOAD_TARGET_RATIO_MASK GENMASK(15, 0)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_CURRENT_PLL 0x0000001cu
|
||||
#define VPU_HW_BTRS_MTL_CURRENT_PLL_RATIO_MASK GENMASK(15, 0)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_PLL_ENABLE 0x00000020u
|
||||
|
||||
#define VPU_HW_BTRS_MTL_FMIN_FUSE 0x00000024u
|
||||
#define VPU_HW_BTRS_MTL_FMIN_FUSE_MIN_RATIO_MASK GENMASK(7, 0)
|
||||
#define VPU_HW_BTRS_MTL_FMIN_FUSE_PN_RATIO_MASK GENMASK(15, 8)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_FMAX_FUSE 0x00000028u
|
||||
#define VPU_HW_BTRS_MTL_FMAX_FUSE_MAX_RATIO_MASK GENMASK(7, 0)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_TILE_FUSE 0x0000002cu
|
||||
#define VPU_HW_BTRS_MTL_TILE_FUSE_VALID_MASK BIT_MASK(0)
|
||||
#define VPU_HW_BTRS_MTL_TILE_FUSE_SKU_MASK GENMASK(3, 2)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_LOCAL_INT_MASK 0x00000030u
|
||||
#define VPU_HW_BTRS_MTL_GLOBAL_INT_MASK 0x00000034u
|
||||
|
||||
#define VPU_HW_BTRS_MTL_PLL_STATUS 0x00000040u
|
||||
#define VPU_HW_BTRS_MTL_PLL_STATUS_LOCK_MASK BIT_MASK(1)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_VPU_STATUS 0x00000044u
|
||||
#define VPU_HW_BTRS_MTL_VPU_STATUS_READY_MASK BIT_MASK(0)
|
||||
#define VPU_HW_BTRS_MTL_VPU_STATUS_IDLE_MASK BIT_MASK(1)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_VPU_IP_RESET 0x00000050u
|
||||
#define VPU_HW_BTRS_MTL_VPU_IP_RESET_TRIGGER_MASK BIT_MASK(0)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_VPU_D0I3_CONTROL 0x00000060u
|
||||
#define VPU_HW_BTRS_MTL_VPU_D0I3_CONTROL_INPROGRESS_MASK BIT_MASK(0)
|
||||
#define VPU_HW_BTRS_MTL_VPU_D0I3_CONTROL_I3_MASK BIT_MASK(2)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_VPU_TELEMETRY_OFFSET 0x00000080u
|
||||
#define VPU_HW_BTRS_MTL_VPU_TELEMETRY_SIZE 0x00000084u
|
||||
#define VPU_HW_BTRS_MTL_VPU_TELEMETRY_ENABLE 0x00000088u
|
||||
|
||||
#define VPU_HW_BTRS_MTL_ATS_ERR_LOG_0 0x000000a0u
|
||||
#define VPU_HW_BTRS_MTL_ATS_ERR_LOG_1 0x000000a4u
|
||||
#define VPU_HW_BTRS_MTL_ATS_ERR_CLEAR 0x000000a8u
|
||||
|
||||
#define VPU_HW_BTRS_MTL_UFI_ERR_LOG 0x000000b0u
|
||||
#define VPU_HW_BTRS_MTL_UFI_ERR_LOG_CQ_ID_MASK GENMASK(11, 0)
|
||||
#define VPU_HW_BTRS_MTL_UFI_ERR_LOG_AXI_ID_MASK GENMASK(19, 12)
|
||||
#define VPU_HW_BTRS_MTL_UFI_ERR_LOG_OPCODE_MASK GENMASK(24, 20)
|
||||
|
||||
#define VPU_HW_BTRS_MTL_UFI_ERR_CLEAR 0x000000b4u
|
||||
|
||||
#define VPU_HW_BTRS_LNL_INTERRUPT_STAT 0x00000000u
|
||||
#define VPU_HW_BTRS_LNL_INTERRUPT_STAT_FREQ_CHANGE_MASK BIT_MASK(0)
|
||||
#define VPU_HW_BTRS_LNL_INTERRUPT_STAT_ATS_ERR_MASK BIT_MASK(1)
|
||||
|
|
@ -79,12 +151,12 @@
|
|||
|
||||
#define VPU_HW_BTRS_LNL_TILE_FUSE 0x00000150u
|
||||
#define VPU_HW_BTRS_LNL_TILE_FUSE_VALID_MASK BIT_MASK(0)
|
||||
#define VPU_HW_BTRS_LNL_TILE_FUSE_CONFIG_MASK GENMASK(6, 1)
|
||||
#define VPU_HW_BTRS_LNL_TILE_FUSE_CONFIG_MASK GENMASK(7, 1)
|
||||
|
||||
#define VPU_HW_BTRS_LNL_VPU_STATUS 0x00000154u
|
||||
#define VPU_HW_BTRS_LNL_VPU_STATUS_READY_MASK BIT_MASK(0)
|
||||
#define VPU_HW_BTRS_LNL_VPU_STATUS_IDLE_MASK BIT_MASK(1)
|
||||
#define VPU_HW_BTRS_LNL_VPU_STATUS_DUP_IDLE_MASK BIT_MASK(2)
|
||||
#define VPU_HW_BTRS_LNL_VPU_STATUS_DPU_IDLE_MASK BIT_MASK(2)
|
||||
#define VPU_HW_BTRS_LNL_VPU_STATUS_CLOCK_RESOURCE_OWN_ACK_MASK BIT_MASK(6)
|
||||
#define VPU_HW_BTRS_LNL_VPU_STATUS_POWER_RESOURCE_OWN_ACK_MASK BIT_MASK(7)
|
||||
#define VPU_HW_BTRS_LNL_VPU_STATUS_PERF_CLK_MASK BIT_MASK(11)
|
||||
|
|
@ -109,4 +181,4 @@
|
|||
#define VPU_HW_BTRS_LNL_FMAX_FUSE 0x00000178u
|
||||
#define VPU_HW_BTRS_LNL_FMAX_FUSE_MAX_RATIO_MASK GENMASK(7, 0)
|
||||
|
||||
#endif /* __IVPU_HW_BTRS_LNL_REG_H__ */
|
||||
#endif /* __IVPU_HW_BTRS_REG_H__ */
|
||||
|
|
@ -7,10 +7,9 @@
|
|||
#include "ivpu_fw.h"
|
||||
#include "ivpu_gem.h"
|
||||
#include "ivpu_hw.h"
|
||||
#include "ivpu_hw_37xx_reg.h"
|
||||
#include "ivpu_hw_40xx_reg.h"
|
||||
#include "ivpu_hw_btrs.h"
|
||||
#include "ivpu_hw_ip.h"
|
||||
#include "ivpu_hw_ip_reg.h"
|
||||
#include "ivpu_hw_reg_io.h"
|
||||
#include "ivpu_mmu.h"
|
||||
#include "ivpu_pm.h"
|
||||
|
|
@ -18,49 +17,27 @@
|
|||
#define TIM_SAFE_ENABLE 0xf1d0dead
|
||||
#define TIM_WATCHDOG_RESET_VALUE 0xffffffff
|
||||
|
||||
#define ICB_0_IRQ_MASK_37XX ((REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, HOST_IPC_FIFO_INT)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_0_INT)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_1_INT)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_2_INT)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, NOC_FIREWALL_INT)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_0_INT)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_1_INT)))
|
||||
#define ICB_0_IRQ_MASK ((REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, HOST_IPC_FIFO_INT)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_0_INT)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_1_INT)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_2_INT)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, NOC_FIREWALL_INT)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_0_INT)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_1_INT)))
|
||||
|
||||
#define ICB_1_IRQ_MASK_37XX ((REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_1, CPU_INT_REDIRECT_2_INT)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_1, CPU_INT_REDIRECT_3_INT)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_1, CPU_INT_REDIRECT_4_INT)))
|
||||
#define ICB_1_IRQ_MASK ((REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_1, CPU_INT_REDIRECT_2_INT)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_1, CPU_INT_REDIRECT_3_INT)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_1, CPU_INT_REDIRECT_4_INT)))
|
||||
|
||||
#define ICB_0_1_IRQ_MASK_37XX ((((u64)ICB_1_IRQ_MASK_37XX) << 32) | ICB_0_IRQ_MASK_37XX)
|
||||
#define ICB_0_1_IRQ_MASK ((((u64)ICB_1_IRQ_MASK) << 32) | ICB_0_IRQ_MASK)
|
||||
|
||||
#define ICB_0_IRQ_MASK_40XX ((REG_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, HOST_IPC_FIFO_INT)) | \
|
||||
(REG_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_0_INT)) | \
|
||||
(REG_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_1_INT)) | \
|
||||
(REG_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_2_INT)) | \
|
||||
(REG_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, NOC_FIREWALL_INT)) | \
|
||||
(REG_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_0_INT)) | \
|
||||
(REG_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_1_INT)))
|
||||
|
||||
#define ICB_1_IRQ_MASK_40XX ((REG_FLD(VPU_40XX_HOST_SS_ICB_STATUS_1, CPU_INT_REDIRECT_2_INT)) | \
|
||||
(REG_FLD(VPU_40XX_HOST_SS_ICB_STATUS_1, CPU_INT_REDIRECT_3_INT)) | \
|
||||
(REG_FLD(VPU_40XX_HOST_SS_ICB_STATUS_1, CPU_INT_REDIRECT_4_INT)))
|
||||
|
||||
#define ICB_0_1_IRQ_MASK_40XX ((((u64)ICB_1_IRQ_MASK_40XX) << 32) | ICB_0_IRQ_MASK_40XX)
|
||||
|
||||
#define ITF_FIREWALL_VIOLATION_MASK_37XX ((REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, CSS_ROM_CMX)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, CSS_DBG)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, CSS_CTRL)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, DEC400)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, MSS_NCE)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, MSS_MBI)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, MSS_MBI_CMX)))
|
||||
|
||||
#define ITF_FIREWALL_VIOLATION_MASK_40XX ((REG_FLD(VPU_40XX_HOST_SS_FW_SOC_IRQ_EN, CSS_ROM_CMX)) | \
|
||||
(REG_FLD(VPU_40XX_HOST_SS_FW_SOC_IRQ_EN, CSS_DBG)) | \
|
||||
(REG_FLD(VPU_40XX_HOST_SS_FW_SOC_IRQ_EN, CSS_CTRL)) | \
|
||||
(REG_FLD(VPU_40XX_HOST_SS_FW_SOC_IRQ_EN, DEC400)) | \
|
||||
(REG_FLD(VPU_40XX_HOST_SS_FW_SOC_IRQ_EN, MSS_NCE)) | \
|
||||
(REG_FLD(VPU_40XX_HOST_SS_FW_SOC_IRQ_EN, MSS_MBI)) | \
|
||||
(REG_FLD(VPU_40XX_HOST_SS_FW_SOC_IRQ_EN, MSS_MBI_CMX)))
|
||||
#define ITF_FIREWALL_VIOLATION_MASK ((REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, CSS_ROM_CMX)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, CSS_DBG)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, CSS_CTRL)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, DEC400)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, MSS_NCE)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, MSS_MBI)) | \
|
||||
(REG_FLD(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, MSS_MBI_CMX)))
|
||||
|
||||
static int wait_for_ip_bar(struct ivpu_device *vdev)
|
||||
{
|
||||
|
|
@ -78,7 +55,7 @@ static void host_ss_rst_clr(struct ivpu_device *vdev)
|
|||
REGV_WR32(VPU_37XX_HOST_SS_CPR_RST_CLR, val);
|
||||
}
|
||||
|
||||
static int host_ss_noc_qreqn_check_37xx(struct ivpu_device *vdev, u32 exp_val)
|
||||
static int host_ss_noc_qreqn_check(struct ivpu_device *vdev, u32 exp_val)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_37XX_HOST_SS_NOC_QREQN);
|
||||
|
||||
|
|
@ -88,25 +65,7 @@ static int host_ss_noc_qreqn_check_37xx(struct ivpu_device *vdev, u32 exp_val)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int host_ss_noc_qreqn_check_40xx(struct ivpu_device *vdev, u32 exp_val)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_40XX_HOST_SS_NOC_QREQN);
|
||||
|
||||
if (!REG_TEST_FLD_NUM(VPU_40XX_HOST_SS_NOC_QREQN, TOP_SOCMMIO, exp_val, val))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int host_ss_noc_qreqn_check(struct ivpu_device *vdev, u32 exp_val)
|
||||
{
|
||||
if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
|
||||
return host_ss_noc_qreqn_check_37xx(vdev, exp_val);
|
||||
else
|
||||
return host_ss_noc_qreqn_check_40xx(vdev, exp_val);
|
||||
}
|
||||
|
||||
static int host_ss_noc_qacceptn_check_37xx(struct ivpu_device *vdev, u32 exp_val)
|
||||
static int host_ss_noc_qacceptn_check(struct ivpu_device *vdev, u32 exp_val)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_37XX_HOST_SS_NOC_QACCEPTN);
|
||||
|
||||
|
|
@ -116,25 +75,7 @@ static int host_ss_noc_qacceptn_check_37xx(struct ivpu_device *vdev, u32 exp_val
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int host_ss_noc_qacceptn_check_40xx(struct ivpu_device *vdev, u32 exp_val)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_40XX_HOST_SS_NOC_QACCEPTN);
|
||||
|
||||
if (!REG_TEST_FLD_NUM(VPU_40XX_HOST_SS_NOC_QACCEPTN, TOP_SOCMMIO, exp_val, val))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int host_ss_noc_qacceptn_check(struct ivpu_device *vdev, u32 exp_val)
|
||||
{
|
||||
if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
|
||||
return host_ss_noc_qacceptn_check_37xx(vdev, exp_val);
|
||||
else
|
||||
return host_ss_noc_qacceptn_check_40xx(vdev, exp_val);
|
||||
}
|
||||
|
||||
static int host_ss_noc_qdeny_check_37xx(struct ivpu_device *vdev, u32 exp_val)
|
||||
static int host_ss_noc_qdeny_check(struct ivpu_device *vdev, u32 exp_val)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_37XX_HOST_SS_NOC_QDENY);
|
||||
|
||||
|
|
@ -144,24 +85,6 @@ static int host_ss_noc_qdeny_check_37xx(struct ivpu_device *vdev, u32 exp_val)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int host_ss_noc_qdeny_check_40xx(struct ivpu_device *vdev, u32 exp_val)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_40XX_HOST_SS_NOC_QDENY);
|
||||
|
||||
if (!REG_TEST_FLD_NUM(VPU_40XX_HOST_SS_NOC_QDENY, TOP_SOCMMIO, exp_val, val))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int host_ss_noc_qdeny_check(struct ivpu_device *vdev, u32 exp_val)
|
||||
{
|
||||
if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
|
||||
return host_ss_noc_qdeny_check_37xx(vdev, exp_val);
|
||||
else
|
||||
return host_ss_noc_qdeny_check_40xx(vdev, exp_val);
|
||||
}
|
||||
|
||||
static int top_noc_qrenqn_check_37xx(struct ivpu_device *vdev, u32 exp_val)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_37XX_TOP_NOC_QREQN);
|
||||
|
|
@ -175,9 +98,9 @@ static int top_noc_qrenqn_check_37xx(struct ivpu_device *vdev, u32 exp_val)
|
|||
|
||||
static int top_noc_qrenqn_check_40xx(struct ivpu_device *vdev, u32 exp_val)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_40XX_TOP_NOC_QREQN);
|
||||
u32 val = REGV_RD32(VPU_37XX_TOP_NOC_QREQN);
|
||||
|
||||
if (!REG_TEST_FLD_NUM(VPU_40XX_TOP_NOC_QREQN, CPU_CTRL, exp_val, val) ||
|
||||
if (!REG_TEST_FLD_NUM(VPU_37XX_TOP_NOC_QREQN, CPU_CTRL, exp_val, val) ||
|
||||
!REG_TEST_FLD_NUM(VPU_40XX_TOP_NOC_QREQN, HOSTIF_L2CACHE, exp_val, val))
|
||||
return -EIO;
|
||||
|
||||
|
|
@ -224,7 +147,7 @@ int ivpu_hw_ip_host_ss_configure(struct ivpu_device *vdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void idle_gen_drive_37xx(struct ivpu_device *vdev, bool enable)
|
||||
static void idle_gen_drive(struct ivpu_device *vdev, bool enable)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_37XX_HOST_SS_AON_VPU_IDLE_GEN);
|
||||
|
||||
|
|
@ -236,51 +159,47 @@ static void idle_gen_drive_37xx(struct ivpu_device *vdev, bool enable)
|
|||
REGV_WR32(VPU_37XX_HOST_SS_AON_VPU_IDLE_GEN, val);
|
||||
}
|
||||
|
||||
static void idle_gen_drive_40xx(struct ivpu_device *vdev, bool enable)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_40XX_HOST_SS_AON_IDLE_GEN);
|
||||
|
||||
if (enable)
|
||||
val = REG_SET_FLD(VPU_40XX_HOST_SS_AON_IDLE_GEN, EN, val);
|
||||
else
|
||||
val = REG_CLR_FLD(VPU_40XX_HOST_SS_AON_IDLE_GEN, EN, val);
|
||||
|
||||
REGV_WR32(VPU_40XX_HOST_SS_AON_IDLE_GEN, val);
|
||||
}
|
||||
|
||||
void ivpu_hw_ip_idle_gen_enable(struct ivpu_device *vdev)
|
||||
{
|
||||
if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
|
||||
idle_gen_drive_37xx(vdev, true);
|
||||
else
|
||||
idle_gen_drive_40xx(vdev, true);
|
||||
idle_gen_drive(vdev, true);
|
||||
}
|
||||
|
||||
void ivpu_hw_ip_idle_gen_disable(struct ivpu_device *vdev)
|
||||
{
|
||||
if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
|
||||
idle_gen_drive_37xx(vdev, false);
|
||||
else
|
||||
idle_gen_drive_40xx(vdev, false);
|
||||
idle_gen_drive(vdev, false);
|
||||
}
|
||||
|
||||
static void
|
||||
pwr_island_delay_set_50xx(struct ivpu_device *vdev, u32 post, u32 post1, u32 post2, u32 status)
|
||||
pwr_island_delay_write(struct ivpu_device *vdev, u32 post, u32 post1, u32 post2, u32 status)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = REGV_RD32(VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY);
|
||||
val = REG_SET_FLD_NUM(VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY, POST_DLY, post, val);
|
||||
val = REG_SET_FLD_NUM(VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY, POST_DLY, post, 0);
|
||||
val = REG_SET_FLD_NUM(VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY, POST1_DLY, post1, val);
|
||||
val = REG_SET_FLD_NUM(VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY, POST2_DLY, post2, val);
|
||||
REGV_WR32(VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY, val);
|
||||
|
||||
val = REGV_RD32(VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY);
|
||||
val = REG_SET_FLD_NUM(VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY, STATUS_DLY, status, val);
|
||||
val = REG_SET_FLD_NUM(VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY, STATUS_DLY, status, 0);
|
||||
REGV_WR32(VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY, val);
|
||||
}
|
||||
|
||||
static void pwr_island_trickle_drive_37xx(struct ivpu_device *vdev, bool enable)
|
||||
static void pwr_island_delay_set_50xx(struct ivpu_device *vdev)
|
||||
{
|
||||
if (vdev->hw->pll.profiling_freq == PLL_PROFILING_FREQ_HIGH)
|
||||
pwr_island_delay_write(vdev, 18, 0, 0, 46);
|
||||
else
|
||||
pwr_island_delay_write(vdev, 0, 0, 0, 3);
|
||||
}
|
||||
|
||||
static void pwr_island_delay_set_60xx(struct ivpu_device *vdev)
|
||||
{
|
||||
if (vdev->hw->pll.profiling_freq == PLL_PROFILING_FREQ_HIGH)
|
||||
pwr_island_delay_write(vdev, 198, 0, 198, 0);
|
||||
else
|
||||
pwr_island_delay_write(vdev, 17, 0, 17, 0);
|
||||
}
|
||||
|
||||
static void pwr_island_trickle_drive(struct ivpu_device *vdev, bool enable)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_37XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0);
|
||||
|
||||
|
|
@ -292,19 +211,7 @@ static void pwr_island_trickle_drive_37xx(struct ivpu_device *vdev, bool enable)
|
|||
REGV_WR32(VPU_37XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0, val);
|
||||
}
|
||||
|
||||
static void pwr_island_trickle_drive_40xx(struct ivpu_device *vdev, bool enable)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_40XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0);
|
||||
|
||||
if (enable)
|
||||
val = REG_SET_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0, CSS_CPU, val);
|
||||
else
|
||||
val = REG_CLR_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0, CSS_CPU, val);
|
||||
|
||||
REGV_WR32(VPU_40XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0, val);
|
||||
}
|
||||
|
||||
static void pwr_island_drive_37xx(struct ivpu_device *vdev, bool enable)
|
||||
static void pwr_island_drive(struct ivpu_device *vdev, bool enable)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_37XX_HOST_SS_AON_PWR_ISLAND_EN0);
|
||||
|
||||
|
|
@ -316,29 +223,11 @@ static void pwr_island_drive_37xx(struct ivpu_device *vdev, bool enable)
|
|||
REGV_WR32(VPU_37XX_HOST_SS_AON_PWR_ISLAND_EN0, val);
|
||||
}
|
||||
|
||||
static void pwr_island_drive_40xx(struct ivpu_device *vdev, bool enable)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0);
|
||||
|
||||
if (enable)
|
||||
val = REG_SET_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, CSS_CPU, val);
|
||||
else
|
||||
val = REG_CLR_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, CSS_CPU, val);
|
||||
|
||||
REGV_WR32(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, val);
|
||||
}
|
||||
|
||||
static void pwr_island_enable(struct ivpu_device *vdev)
|
||||
{
|
||||
if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) {
|
||||
pwr_island_trickle_drive_37xx(vdev, true);
|
||||
ndelay(500);
|
||||
pwr_island_drive_37xx(vdev, true);
|
||||
} else {
|
||||
pwr_island_trickle_drive_40xx(vdev, true);
|
||||
ndelay(500);
|
||||
pwr_island_drive_40xx(vdev, true);
|
||||
}
|
||||
pwr_island_trickle_drive(vdev, true);
|
||||
ndelay(500);
|
||||
pwr_island_drive(vdev, true);
|
||||
}
|
||||
|
||||
static int wait_for_pwr_island_status(struct ivpu_device *vdev, u32 exp_val)
|
||||
|
|
@ -346,15 +235,11 @@ static int wait_for_pwr_island_status(struct ivpu_device *vdev, u32 exp_val)
|
|||
if (IVPU_WA(punit_disabled))
|
||||
return 0;
|
||||
|
||||
if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
|
||||
return REGV_POLL_FLD(VPU_37XX_HOST_SS_AON_PWR_ISLAND_STATUS0, MSS_CPU, exp_val,
|
||||
vdev->timeout.pwr_island_status);
|
||||
else
|
||||
return REGV_POLL_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_STATUS0, CSS_CPU, exp_val,
|
||||
vdev->timeout.pwr_island_status);
|
||||
return REGV_POLL_FLD(VPU_37XX_HOST_SS_AON_PWR_ISLAND_STATUS0, MSS_CPU, exp_val,
|
||||
vdev->timeout.pwr_island_status);
|
||||
}
|
||||
|
||||
static void pwr_island_isolation_drive_37xx(struct ivpu_device *vdev, bool enable)
|
||||
static void pwr_island_isolation_drive(struct ivpu_device *vdev, bool enable)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_37XX_HOST_SS_AON_PWR_ISO_EN0);
|
||||
|
||||
|
|
@ -366,26 +251,6 @@ static void pwr_island_isolation_drive_37xx(struct ivpu_device *vdev, bool enabl
|
|||
REGV_WR32(VPU_37XX_HOST_SS_AON_PWR_ISO_EN0, val);
|
||||
}
|
||||
|
||||
static void pwr_island_isolation_drive_40xx(struct ivpu_device *vdev, bool enable)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_40XX_HOST_SS_AON_PWR_ISO_EN0);
|
||||
|
||||
if (enable)
|
||||
val = REG_SET_FLD(VPU_40XX_HOST_SS_AON_PWR_ISO_EN0, CSS_CPU, val);
|
||||
else
|
||||
val = REG_CLR_FLD(VPU_40XX_HOST_SS_AON_PWR_ISO_EN0, CSS_CPU, val);
|
||||
|
||||
REGV_WR32(VPU_40XX_HOST_SS_AON_PWR_ISO_EN0, val);
|
||||
}
|
||||
|
||||
static void pwr_island_isolation_drive(struct ivpu_device *vdev, bool enable)
|
||||
{
|
||||
if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
|
||||
pwr_island_isolation_drive_37xx(vdev, enable);
|
||||
else
|
||||
pwr_island_isolation_drive_40xx(vdev, enable);
|
||||
}
|
||||
|
||||
static void pwr_island_isolation_disable(struct ivpu_device *vdev)
|
||||
{
|
||||
pwr_island_isolation_drive(vdev, false);
|
||||
|
|
@ -485,7 +350,7 @@ static void host_ss_rst_enable(struct ivpu_device *vdev)
|
|||
host_ss_rst_drive(vdev, true);
|
||||
}
|
||||
|
||||
static void host_ss_noc_qreqn_top_socmmio_drive_37xx(struct ivpu_device *vdev, bool enable)
|
||||
static void host_ss_noc_qreqn_top_socmmio_drive(struct ivpu_device *vdev, bool enable)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_37XX_HOST_SS_NOC_QREQN);
|
||||
|
||||
|
|
@ -496,25 +361,6 @@ static void host_ss_noc_qreqn_top_socmmio_drive_37xx(struct ivpu_device *vdev, b
|
|||
REGV_WR32(VPU_37XX_HOST_SS_NOC_QREQN, val);
|
||||
}
|
||||
|
||||
static void host_ss_noc_qreqn_top_socmmio_drive_40xx(struct ivpu_device *vdev, bool enable)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_40XX_HOST_SS_NOC_QREQN);
|
||||
|
||||
if (enable)
|
||||
val = REG_SET_FLD(VPU_40XX_HOST_SS_NOC_QREQN, TOP_SOCMMIO, val);
|
||||
else
|
||||
val = REG_CLR_FLD(VPU_40XX_HOST_SS_NOC_QREQN, TOP_SOCMMIO, val);
|
||||
REGV_WR32(VPU_40XX_HOST_SS_NOC_QREQN, val);
|
||||
}
|
||||
|
||||
static void host_ss_noc_qreqn_top_socmmio_drive(struct ivpu_device *vdev, bool enable)
|
||||
{
|
||||
if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
|
||||
host_ss_noc_qreqn_top_socmmio_drive_37xx(vdev, enable);
|
||||
else
|
||||
host_ss_noc_qreqn_top_socmmio_drive_40xx(vdev, enable);
|
||||
}
|
||||
|
||||
static int host_ss_axi_drive(struct ivpu_device *vdev, bool enable)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -536,17 +382,17 @@ static int host_ss_axi_drive(struct ivpu_device *vdev, bool enable)
|
|||
|
||||
static void top_noc_qreqn_drive_40xx(struct ivpu_device *vdev, bool enable)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_40XX_TOP_NOC_QREQN);
|
||||
u32 val = REGV_RD32(VPU_37XX_TOP_NOC_QREQN);
|
||||
|
||||
if (enable) {
|
||||
val = REG_SET_FLD(VPU_40XX_TOP_NOC_QREQN, CPU_CTRL, val);
|
||||
val = REG_SET_FLD(VPU_37XX_TOP_NOC_QREQN, CPU_CTRL, val);
|
||||
val = REG_SET_FLD(VPU_40XX_TOP_NOC_QREQN, HOSTIF_L2CACHE, val);
|
||||
} else {
|
||||
val = REG_CLR_FLD(VPU_40XX_TOP_NOC_QREQN, CPU_CTRL, val);
|
||||
val = REG_CLR_FLD(VPU_37XX_TOP_NOC_QREQN, CPU_CTRL, val);
|
||||
val = REG_CLR_FLD(VPU_40XX_TOP_NOC_QREQN, HOSTIF_L2CACHE, val);
|
||||
}
|
||||
|
||||
REGV_WR32(VPU_40XX_TOP_NOC_QREQN, val);
|
||||
REGV_WR32(VPU_37XX_TOP_NOC_QREQN, val);
|
||||
}
|
||||
|
||||
static void top_noc_qreqn_drive_37xx(struct ivpu_device *vdev, bool enable)
|
||||
|
|
@ -590,9 +436,9 @@ static int top_noc_qacceptn_check_37xx(struct ivpu_device *vdev, u32 exp_val)
|
|||
|
||||
static int top_noc_qacceptn_check_40xx(struct ivpu_device *vdev, u32 exp_val)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_40XX_TOP_NOC_QACCEPTN);
|
||||
u32 val = REGV_RD32(VPU_37XX_TOP_NOC_QACCEPTN);
|
||||
|
||||
if (!REG_TEST_FLD_NUM(VPU_40XX_TOP_NOC_QACCEPTN, CPU_CTRL, exp_val, val) ||
|
||||
if (!REG_TEST_FLD_NUM(VPU_37XX_TOP_NOC_QACCEPTN, CPU_CTRL, exp_val, val) ||
|
||||
!REG_TEST_FLD_NUM(VPU_40XX_TOP_NOC_QACCEPTN, HOSTIF_L2CACHE, exp_val, val))
|
||||
return -EIO;
|
||||
|
||||
|
|
@ -620,9 +466,9 @@ static int top_noc_qdeny_check_37xx(struct ivpu_device *vdev, u32 exp_val)
|
|||
|
||||
static int top_noc_qdeny_check_40xx(struct ivpu_device *vdev, u32 exp_val)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_40XX_TOP_NOC_QDENY);
|
||||
u32 val = REGV_RD32(VPU_37XX_TOP_NOC_QDENY);
|
||||
|
||||
if (!REG_TEST_FLD_NUM(VPU_40XX_TOP_NOC_QDENY, CPU_CTRL, exp_val, val) ||
|
||||
if (!REG_TEST_FLD_NUM(VPU_37XX_TOP_NOC_QDENY, CPU_CTRL, exp_val, val) ||
|
||||
!REG_TEST_FLD_NUM(VPU_40XX_TOP_NOC_QDENY, HOSTIF_L2CACHE, exp_val, val))
|
||||
return -EIO;
|
||||
|
||||
|
|
@ -675,35 +521,19 @@ static void dpu_active_drive_37xx(struct ivpu_device *vdev, bool enable)
|
|||
|
||||
static void pwr_island_delay_set(struct ivpu_device *vdev)
|
||||
{
|
||||
bool high = vdev->hw->pll.profiling_freq == PLL_PROFILING_FREQ_HIGH;
|
||||
u32 post, post1, post2, status;
|
||||
|
||||
if (ivpu_hw_ip_gen(vdev) < IVPU_HW_IP_50XX)
|
||||
switch (ivpu_hw_ip_gen(vdev)) {
|
||||
case IVPU_HW_IP_37XX:
|
||||
case IVPU_HW_IP_40XX:
|
||||
return;
|
||||
|
||||
switch (ivpu_device_id(vdev)) {
|
||||
case PCI_DEVICE_ID_WCL:
|
||||
case PCI_DEVICE_ID_PTL_P:
|
||||
post = high ? 18 : 0;
|
||||
post1 = 0;
|
||||
post2 = 0;
|
||||
status = high ? 46 : 3;
|
||||
break;
|
||||
case IVPU_HW_IP_50XX:
|
||||
pwr_island_delay_set_50xx(vdev);
|
||||
return;
|
||||
|
||||
case PCI_DEVICE_ID_NVL:
|
||||
post = high ? 198 : 17;
|
||||
post1 = 0;
|
||||
post2 = high ? 198 : 17;
|
||||
status = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
dump_stack();
|
||||
ivpu_err(vdev, "Unknown device ID\n");
|
||||
case IVPU_HW_IP_60XX:
|
||||
pwr_island_delay_set_60xx(vdev);
|
||||
return;
|
||||
}
|
||||
|
||||
pwr_island_delay_set_50xx(vdev, post, post1, post2, status);
|
||||
}
|
||||
|
||||
int ivpu_hw_ip_pwr_domain_enable(struct ivpu_device *vdev)
|
||||
|
|
@ -760,7 +590,7 @@ static void ivpu_hw_ip_snoop_disable_37xx(struct ivpu_device *vdev)
|
|||
|
||||
static void ivpu_hw_ip_snoop_disable_40xx(struct ivpu_device *vdev)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES);
|
||||
u32 val = REGV_RD32(VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES);
|
||||
|
||||
val = REG_SET_FLD(VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES, SNOOP_OVERRIDE_EN, val);
|
||||
val = REG_SET_FLD(VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES, AW_SNOOP_OVERRIDE, val);
|
||||
|
|
@ -770,7 +600,7 @@ static void ivpu_hw_ip_snoop_disable_40xx(struct ivpu_device *vdev)
|
|||
else
|
||||
val = REG_CLR_FLD(VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES, AR_SNOOP_OVERRIDE, val);
|
||||
|
||||
REGV_WR32(VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES, val);
|
||||
REGV_WR32(VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES, val);
|
||||
}
|
||||
|
||||
void ivpu_hw_ip_snoop_disable(struct ivpu_device *vdev)
|
||||
|
|
@ -795,24 +625,29 @@ static void ivpu_hw_ip_tbu_mmu_enable_37xx(struct ivpu_device *vdev)
|
|||
|
||||
static void ivpu_hw_ip_tbu_mmu_enable_40xx(struct ivpu_device *vdev)
|
||||
{
|
||||
u32 val = REGV_RD32(VPU_40XX_HOST_IF_TBU_MMUSSIDV);
|
||||
u32 val = REGV_RD32(VPU_37XX_HOST_IF_TBU_MMUSSIDV);
|
||||
|
||||
val = REG_SET_FLD(VPU_40XX_HOST_IF_TBU_MMUSSIDV, TBU0_AWMMUSSIDV, val);
|
||||
val = REG_SET_FLD(VPU_40XX_HOST_IF_TBU_MMUSSIDV, TBU0_ARMMUSSIDV, val);
|
||||
val = REG_SET_FLD(VPU_40XX_HOST_IF_TBU_MMUSSIDV, TBU1_AWMMUSSIDV, val);
|
||||
val = REG_SET_FLD(VPU_40XX_HOST_IF_TBU_MMUSSIDV, TBU1_ARMMUSSIDV, val);
|
||||
val = REG_SET_FLD(VPU_40XX_HOST_IF_TBU_MMUSSIDV, TBU2_AWMMUSSIDV, val);
|
||||
val = REG_SET_FLD(VPU_40XX_HOST_IF_TBU_MMUSSIDV, TBU2_ARMMUSSIDV, val);
|
||||
val = REG_SET_FLD(VPU_37XX_HOST_IF_TBU_MMUSSIDV, TBU0_AWMMUSSIDV, val);
|
||||
val = REG_SET_FLD(VPU_37XX_HOST_IF_TBU_MMUSSIDV, TBU0_ARMMUSSIDV, val);
|
||||
val = REG_SET_FLD(VPU_37XX_HOST_IF_TBU_MMUSSIDV, TBU1_AWMMUSSIDV, val);
|
||||
val = REG_SET_FLD(VPU_37XX_HOST_IF_TBU_MMUSSIDV, TBU1_ARMMUSSIDV, val);
|
||||
val = REG_SET_FLD(VPU_37XX_HOST_IF_TBU_MMUSSIDV, TBU2_AWMMUSSIDV, val);
|
||||
val = REG_SET_FLD(VPU_37XX_HOST_IF_TBU_MMUSSIDV, TBU2_ARMMUSSIDV, val);
|
||||
|
||||
REGV_WR32(VPU_40XX_HOST_IF_TBU_MMUSSIDV, val);
|
||||
REGV_WR32(VPU_37XX_HOST_IF_TBU_MMUSSIDV, val);
|
||||
}
|
||||
|
||||
void ivpu_hw_ip_tbu_mmu_enable(struct ivpu_device *vdev)
|
||||
{
|
||||
if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
|
||||
switch (ivpu_hw_ip_gen(vdev)) {
|
||||
case IVPU_HW_IP_37XX:
|
||||
return ivpu_hw_ip_tbu_mmu_enable_37xx(vdev);
|
||||
else
|
||||
|
||||
case IVPU_HW_IP_40XX:
|
||||
case IVPU_HW_IP_50XX:
|
||||
case IVPU_HW_IP_60XX:
|
||||
return ivpu_hw_ip_tbu_mmu_enable_40xx(vdev);
|
||||
}
|
||||
}
|
||||
|
||||
static inline u64 get_entry_point_addr(struct ivpu_device *vdev)
|
||||
|
|
@ -936,29 +771,22 @@ static int soc_cpu_boot_60xx(struct ivpu_device *vdev)
|
|||
|
||||
int ivpu_hw_ip_soc_cpu_boot(struct ivpu_device *vdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (ivpu_hw_ip_gen(vdev)) {
|
||||
case IVPU_HW_IP_37XX:
|
||||
ret = soc_cpu_boot_37xx(vdev);
|
||||
break;
|
||||
|
||||
case IVPU_HW_IP_40XX:
|
||||
case IVPU_HW_IP_50XX:
|
||||
ret = soc_cpu_boot_40xx(vdev);
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = soc_cpu_boot_60xx(vdev);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ivpu_dbg(vdev, PM, "Booting firmware, mode: %s\n",
|
||||
ivpu_fw_is_warm_boot(vdev) ? "warm boot" : "cold boot");
|
||||
|
||||
return 0;
|
||||
switch (ivpu_hw_ip_gen(vdev)) {
|
||||
case IVPU_HW_IP_37XX:
|
||||
return soc_cpu_boot_37xx(vdev);
|
||||
|
||||
case IVPU_HW_IP_40XX:
|
||||
case IVPU_HW_IP_50XX:
|
||||
return soc_cpu_boot_40xx(vdev);
|
||||
|
||||
case IVPU_HW_IP_60XX:
|
||||
return soc_cpu_boot_60xx(vdev);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void wdt_disable_37xx(struct ivpu_device *vdev)
|
||||
|
|
@ -1002,55 +830,30 @@ void ivpu_hw_ip_wdt_disable(struct ivpu_device *vdev)
|
|||
return wdt_disable_40xx(vdev);
|
||||
}
|
||||
|
||||
static u32 ipc_rx_count_get_37xx(struct ivpu_device *vdev)
|
||||
u32 ivpu_hw_ip_ipc_rx_count_get(struct ivpu_device *vdev)
|
||||
{
|
||||
u32 count = readl(vdev->regv + VPU_37XX_HOST_SS_TIM_IPC_FIFO_STAT);
|
||||
|
||||
return REG_GET_FLD(VPU_37XX_HOST_SS_TIM_IPC_FIFO_STAT, FILL_LEVEL, count);
|
||||
}
|
||||
|
||||
static u32 ipc_rx_count_get_40xx(struct ivpu_device *vdev)
|
||||
{
|
||||
u32 count = readl(vdev->regv + VPU_40XX_HOST_SS_TIM_IPC_FIFO_STAT);
|
||||
|
||||
return REG_GET_FLD(VPU_40XX_HOST_SS_TIM_IPC_FIFO_STAT, FILL_LEVEL, count);
|
||||
}
|
||||
|
||||
u32 ivpu_hw_ip_ipc_rx_count_get(struct ivpu_device *vdev)
|
||||
{
|
||||
if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
|
||||
return ipc_rx_count_get_37xx(vdev);
|
||||
else
|
||||
return ipc_rx_count_get_40xx(vdev);
|
||||
}
|
||||
|
||||
void ivpu_hw_ip_irq_enable(struct ivpu_device *vdev)
|
||||
{
|
||||
if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) {
|
||||
REGV_WR32(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, ITF_FIREWALL_VIOLATION_MASK_37XX);
|
||||
REGV_WR64(VPU_37XX_HOST_SS_ICB_ENABLE_0, ICB_0_1_IRQ_MASK_37XX);
|
||||
} else {
|
||||
REGV_WR32(VPU_40XX_HOST_SS_FW_SOC_IRQ_EN, ITF_FIREWALL_VIOLATION_MASK_40XX);
|
||||
REGV_WR64(VPU_40XX_HOST_SS_ICB_ENABLE_0, ICB_0_1_IRQ_MASK_40XX);
|
||||
}
|
||||
REGV_WR32(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, ITF_FIREWALL_VIOLATION_MASK);
|
||||
REGV_WR64(VPU_37XX_HOST_SS_ICB_ENABLE_0, ICB_0_1_IRQ_MASK);
|
||||
}
|
||||
|
||||
void ivpu_hw_ip_irq_disable(struct ivpu_device *vdev)
|
||||
{
|
||||
if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) {
|
||||
REGV_WR64(VPU_37XX_HOST_SS_ICB_ENABLE_0, 0x0ull);
|
||||
REGV_WR32(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, 0x0);
|
||||
} else {
|
||||
REGV_WR64(VPU_40XX_HOST_SS_ICB_ENABLE_0, 0x0ull);
|
||||
REGV_WR32(VPU_40XX_HOST_SS_FW_SOC_IRQ_EN, 0x0ul);
|
||||
}
|
||||
REGV_WR64(VPU_37XX_HOST_SS_ICB_ENABLE_0, 0x0ull);
|
||||
REGV_WR32(VPU_37XX_HOST_SS_FW_SOC_IRQ_EN, 0x0);
|
||||
}
|
||||
|
||||
static void diagnose_failure_37xx(struct ivpu_device *vdev)
|
||||
void ivpu_hw_ip_diagnose_failure(struct ivpu_device *vdev)
|
||||
{
|
||||
u32 reg = REGV_RD32(VPU_37XX_HOST_SS_ICB_STATUS_0) & ICB_0_IRQ_MASK_37XX;
|
||||
u32 reg = REGV_RD32(VPU_37XX_HOST_SS_ICB_STATUS_0) & ICB_0_IRQ_MASK;
|
||||
|
||||
if (ipc_rx_count_get_37xx(vdev))
|
||||
if (ivpu_hw_ip_ipc_rx_count_get(vdev))
|
||||
ivpu_err(vdev, "IPC FIFO queue not empty, missed IPC IRQ");
|
||||
|
||||
if (REG_TEST_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_0_INT, reg))
|
||||
|
|
@ -1063,37 +866,9 @@ static void diagnose_failure_37xx(struct ivpu_device *vdev)
|
|||
ivpu_err(vdev, "NOC Firewall irq detected\n");
|
||||
}
|
||||
|
||||
static void diagnose_failure_40xx(struct ivpu_device *vdev)
|
||||
{
|
||||
u32 reg = REGV_RD32(VPU_40XX_HOST_SS_ICB_STATUS_0) & ICB_0_IRQ_MASK_40XX;
|
||||
|
||||
if (ipc_rx_count_get_40xx(vdev))
|
||||
ivpu_err(vdev, "IPC FIFO queue not empty, missed IPC IRQ");
|
||||
|
||||
if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_0_INT, reg))
|
||||
ivpu_err(vdev, "WDT MSS timeout detected\n");
|
||||
|
||||
if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_1_INT, reg))
|
||||
ivpu_err(vdev, "WDT NCE timeout detected\n");
|
||||
|
||||
if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, NOC_FIREWALL_INT, reg))
|
||||
ivpu_err(vdev, "NOC Firewall irq detected\n");
|
||||
}
|
||||
|
||||
void ivpu_hw_ip_diagnose_failure(struct ivpu_device *vdev)
|
||||
{
|
||||
if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
|
||||
diagnose_failure_37xx(vdev);
|
||||
else
|
||||
diagnose_failure_40xx(vdev);
|
||||
}
|
||||
|
||||
void ivpu_hw_ip_irq_clear(struct ivpu_device *vdev)
|
||||
{
|
||||
if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
|
||||
REGV_WR64(VPU_37XX_HOST_SS_ICB_CLEAR_0, ICB_0_1_IRQ_MASK_37XX);
|
||||
else
|
||||
REGV_WR64(VPU_40XX_HOST_SS_ICB_CLEAR_0, ICB_0_1_IRQ_MASK_40XX);
|
||||
REGV_WR64(VPU_37XX_HOST_SS_ICB_CLEAR_0, ICB_0_1_IRQ_MASK);
|
||||
}
|
||||
|
||||
static void irq_wdt_nce_handler(struct ivpu_device *vdev)
|
||||
|
|
@ -1116,9 +891,9 @@ static void irq_noc_firewall_handler(struct ivpu_device *vdev)
|
|||
}
|
||||
|
||||
/* Handler for IRQs from NPU core */
|
||||
bool ivpu_hw_ip_irq_handler_37xx(struct ivpu_device *vdev, int irq)
|
||||
bool ivpu_hw_ip_irq_handler(struct ivpu_device *vdev, int irq)
|
||||
{
|
||||
u32 status = REGV_RD32(VPU_37XX_HOST_SS_ICB_STATUS_0) & ICB_0_IRQ_MASK_37XX;
|
||||
u32 status = REGV_RD32(VPU_37XX_HOST_SS_ICB_STATUS_0) & ICB_0_IRQ_MASK;
|
||||
|
||||
if (!status)
|
||||
return false;
|
||||
|
|
@ -1149,40 +924,6 @@ bool ivpu_hw_ip_irq_handler_37xx(struct ivpu_device *vdev, int irq)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Handler for IRQs from NPU core */
|
||||
bool ivpu_hw_ip_irq_handler_40xx(struct ivpu_device *vdev, int irq)
|
||||
{
|
||||
u32 status = REGV_RD32(VPU_40XX_HOST_SS_ICB_STATUS_0) & ICB_0_IRQ_MASK_40XX;
|
||||
|
||||
if (!status)
|
||||
return false;
|
||||
|
||||
REGV_WR32(VPU_40XX_HOST_SS_ICB_CLEAR_0, status);
|
||||
|
||||
if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_0_INT, status))
|
||||
ivpu_mmu_irq_evtq_handler(vdev);
|
||||
|
||||
if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, HOST_IPC_FIFO_INT, status))
|
||||
ivpu_ipc_irq_handler(vdev);
|
||||
|
||||
if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_1_INT, status))
|
||||
ivpu_dbg(vdev, IRQ, "MMU sync complete\n");
|
||||
|
||||
if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_2_INT, status))
|
||||
ivpu_mmu_irq_gerr_handler(vdev);
|
||||
|
||||
if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_0_INT, status))
|
||||
irq_wdt_mss_handler(vdev);
|
||||
|
||||
if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, CPU_INT_REDIRECT_1_INT, status))
|
||||
irq_wdt_nce_handler(vdev);
|
||||
|
||||
if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, NOC_FIREWALL_INT, status))
|
||||
irq_noc_firewall_handler(vdev);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void db_set_37xx(struct ivpu_device *vdev, u32 db_id)
|
||||
{
|
||||
u32 reg_stride = VPU_37XX_CPU_SS_DOORBELL_1 - VPU_37XX_CPU_SS_DOORBELL_0;
|
||||
|
|
@ -1209,10 +950,7 @@ void ivpu_hw_ip_db_set(struct ivpu_device *vdev, u32 db_id)
|
|||
|
||||
u32 ivpu_hw_ip_ipc_rx_addr_get(struct ivpu_device *vdev)
|
||||
{
|
||||
if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX)
|
||||
return REGV_RD32(VPU_37XX_HOST_SS_TIM_IPC_FIFO_ATM);
|
||||
else
|
||||
return REGV_RD32(VPU_40XX_HOST_SS_TIM_IPC_FIFO_ATM);
|
||||
return REGV_RD32(VPU_37XX_HOST_SS_TIM_IPC_FIFO_ATM);
|
||||
}
|
||||
|
||||
void ivpu_hw_ip_ipc_tx_set(struct ivpu_device *vdev, u32 vpu_addr)
|
||||
|
|
|
|||
|
|
@ -22,8 +22,7 @@ void ivpu_hw_ip_wdt_disable(struct ivpu_device *vdev);
|
|||
void ivpu_hw_ip_diagnose_failure(struct ivpu_device *vdev);
|
||||
u32 ivpu_hw_ip_ipc_rx_count_get(struct ivpu_device *vdev);
|
||||
void ivpu_hw_ip_irq_clear(struct ivpu_device *vdev);
|
||||
bool ivpu_hw_ip_irq_handler_37xx(struct ivpu_device *vdev, int irq);
|
||||
bool ivpu_hw_ip_irq_handler_40xx(struct ivpu_device *vdev, int irq);
|
||||
bool ivpu_hw_ip_irq_handler(struct ivpu_device *vdev, int irq);
|
||||
void ivpu_hw_ip_db_set(struct ivpu_device *vdev, u32 db_id);
|
||||
u32 ivpu_hw_ip_ipc_rx_addr_get(struct ivpu_device *vdev);
|
||||
void ivpu_hw_ip_ipc_tx_set(struct ivpu_device *vdev, u32 vpu_addr);
|
||||
|
|
|
|||
|
|
@ -1,18 +1,28 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2020-2023 Intel Corporation
|
||||
* Copyright (C) 2020-2026 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __IVPU_HW_37XX_REG_H__
|
||||
#define __IVPU_HW_37XX_REG_H__
|
||||
#ifndef __IVPU_HW_IP_REG_H__
|
||||
#define __IVPU_HW_IP_REG_H__
|
||||
|
||||
#include <linux/bits.h>
|
||||
|
||||
#define VPU_40XX_HOST_SS_CPR_CLK_EN 0x00000080u
|
||||
#define VPU_40XX_HOST_SS_CPR_CLK_EN_TOP_NOC_MASK BIT_MASK(1)
|
||||
#define VPU_40XX_HOST_SS_CPR_CLK_EN_DSS_MAS_MASK BIT_MASK(10)
|
||||
#define VPU_40XX_HOST_SS_CPR_CLK_EN_CSS_MAS_MASK BIT_MASK(11)
|
||||
|
||||
#define VPU_37XX_HOST_SS_CPR_CLK_SET 0x00000084u
|
||||
#define VPU_37XX_HOST_SS_CPR_CLK_SET_TOP_NOC_MASK BIT_MASK(1)
|
||||
#define VPU_37XX_HOST_SS_CPR_CLK_SET_DSS_MAS_MASK BIT_MASK(10)
|
||||
#define VPU_37XX_HOST_SS_CPR_CLK_SET_MSS_MAS_MASK BIT_MASK(11)
|
||||
|
||||
#define VPU_40XX_HOST_SS_CPR_RST_EN 0x00000090u
|
||||
#define VPU_40XX_HOST_SS_CPR_RST_EN_TOP_NOC_MASK BIT_MASK(1)
|
||||
#define VPU_40XX_HOST_SS_CPR_RST_EN_DSS_MAS_MASK BIT_MASK(10)
|
||||
#define VPU_40XX_HOST_SS_CPR_RST_EN_CSS_MAS_MASK BIT_MASK(11)
|
||||
|
||||
#define VPU_37XX_HOST_SS_CPR_RST_SET 0x00000094u
|
||||
#define VPU_37XX_HOST_SS_CPR_RST_SET_TOP_NOC_MASK BIT_MASK(1)
|
||||
#define VPU_37XX_HOST_SS_CPR_RST_SET_DSS_MAS_MASK BIT_MASK(10)
|
||||
|
|
@ -29,6 +39,8 @@
|
|||
#define VPU_37XX_HOST_SS_HW_VERSION_SOC_NUMBER_MASK GENMASK(15, 8)
|
||||
#define VPU_37XX_HOST_SS_HW_VERSION_VPU_GENERATION_MASK GENMASK(23, 16)
|
||||
|
||||
#define VPU_40XX_HOST_SS_SW_VERSION 0x0000010cu
|
||||
|
||||
#define VPU_37XX_HOST_SS_GEN_CTRL 0x00000118u
|
||||
#define VPU_37XX_HOST_SS_GEN_CTRL_PS_MASK GENMASK(31, 29)
|
||||
|
||||
|
|
@ -44,14 +56,17 @@
|
|||
#define VPU_37XX_TOP_NOC_QREQN 0x00000160u
|
||||
#define VPU_37XX_TOP_NOC_QREQN_CPU_CTRL_MASK BIT_MASK(0)
|
||||
#define VPU_37XX_TOP_NOC_QREQN_HOSTIF_L2CACHE_MASK BIT_MASK(1)
|
||||
#define VPU_40XX_TOP_NOC_QREQN_HOSTIF_L2CACHE_MASK BIT_MASK(2)
|
||||
|
||||
#define VPU_37XX_TOP_NOC_QACCEPTN 0x00000164u
|
||||
#define VPU_37XX_TOP_NOC_QACCEPTN_CPU_CTRL_MASK BIT_MASK(0)
|
||||
#define VPU_37XX_TOP_NOC_QACCEPTN_HOSTIF_L2CACHE_MASK BIT_MASK(1)
|
||||
#define VPU_40XX_TOP_NOC_QACCEPTN_HOSTIF_L2CACHE_MASK BIT_MASK(2)
|
||||
|
||||
#define VPU_37XX_TOP_NOC_QDENY 0x00000168u
|
||||
#define VPU_37XX_TOP_NOC_QDENY_CPU_CTRL_MASK BIT_MASK(0)
|
||||
#define VPU_37XX_TOP_NOC_QDENY_HOSTIF_L2CACHE_MASK BIT_MASK(1)
|
||||
#define VPU_40XX_TOP_NOC_QDENY_HOSTIF_L2CACHE_MASK BIT_MASK(2)
|
||||
|
||||
#define VPU_37XX_HOST_SS_FW_SOC_IRQ_EN 0x00000170u
|
||||
#define VPU_37XX_HOST_SS_FW_SOC_IRQ_EN_CSS_ROM_CMX_MASK BIT_MASK(0)
|
||||
|
|
@ -83,6 +98,7 @@
|
|||
#define VPU_37XX_HOST_SS_ICB_CLEAR_0 0x00010220u
|
||||
#define VPU_37XX_HOST_SS_ICB_CLEAR_1 0x00010224u
|
||||
#define VPU_37XX_HOST_SS_ICB_ENABLE_0 0x00010240u
|
||||
#define VPU_40XX_HOST_SS_ICB_ENABLE_1 0x00010244u
|
||||
|
||||
#define VPU_37XX_HOST_SS_TIM_IPC_FIFO_ATM 0x000200f4u
|
||||
|
||||
|
|
@ -104,12 +120,29 @@
|
|||
#define VPU_37XX_HOST_SS_AON_PWR_ISLAND_STATUS0 0x0003002cu
|
||||
#define VPU_37XX_HOST_SS_AON_PWR_ISLAND_STATUS0_MSS_CPU_MASK BIT_MASK(3)
|
||||
|
||||
#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY 0x00030068u
|
||||
#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY_POST_DLY_MASK GENMASK(7, 0)
|
||||
#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY_POST1_DLY_MASK GENMASK(15, 8)
|
||||
#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY_POST2_DLY_MASK GENMASK(23, 16)
|
||||
|
||||
#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY 0x0003006cu
|
||||
#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY_STATUS_DLY_MASK GENMASK(7, 0)
|
||||
|
||||
#define VPU_37XX_HOST_SS_AON_VPU_IDLE_GEN 0x00030200u
|
||||
#define VPU_37XX_HOST_SS_AON_VPU_IDLE_GEN_EN_MASK BIT_MASK(0)
|
||||
#define VPU_40XX_HOST_SS_AON_VPU_IDLE_GEN_HW_PG_EN_MASK BIT_MASK(1)
|
||||
|
||||
#define VPU_37XX_HOST_SS_AON_DPU_ACTIVE 0x00030204u
|
||||
#define VPU_37XX_HOST_SS_AON_DPU_ACTIVE_DPU_ACTIVE_MASK BIT_MASK(0)
|
||||
|
||||
#define VPU_50XX_HOST_SS_AON_FABRIC_REQ_OVERRIDE 0x00030210u
|
||||
#define VPU_50XX_HOST_SS_AON_FABRIC_REQ_OVERRIDE_REQ_OVERRIDE_MASK BIT_MASK(0)
|
||||
|
||||
#define VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO 0x00040040u
|
||||
#define VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO_DONE_MASK BIT_MASK(0)
|
||||
#define VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO_IOSF_RS_ID_MASK GENMASK(2, 1)
|
||||
#define VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO_IMAGE_LOCATION_MASK GENMASK(31, 3)
|
||||
|
||||
#define VPU_37XX_HOST_SS_LOADING_ADDRESS_LO 0x00041040u
|
||||
#define VPU_37XX_HOST_SS_LOADING_ADDRESS_LO_DONE_MASK BIT_MASK(0)
|
||||
#define VPU_37XX_HOST_SS_LOADING_ADDRESS_LO_IOSF_RS_ID_MASK GENMASK(2, 1)
|
||||
|
|
@ -126,6 +159,9 @@
|
|||
#define VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES_NOSNOOP_OVERRIDE_EN_MASK BIT_MASK(3)
|
||||
#define VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES_AW_NOSNOOP_OVERRIDE_MASK BIT_MASK(4)
|
||||
#define VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES_AR_NOSNOOP_OVERRIDE_MASK BIT_MASK(5)
|
||||
#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES_SNOOP_OVERRIDE_EN_MASK BIT_MASK(3)
|
||||
#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES_AW_SNOOP_OVERRIDE_MASK BIT_MASK(4)
|
||||
#define VPU_40XX_HOST_IF_TCU_PTW_OVERRIDES_AR_SNOOP_OVERRIDE_MASK BIT_MASK(5)
|
||||
#define VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES_PTW_AW_CONTEXT_FLAG_MASK GENMASK(10, 6)
|
||||
#define VPU_37XX_HOST_IF_TCU_PTW_OVERRIDES_PTW_AR_CONTEXT_FLAG_MASK GENMASK(15, 11)
|
||||
|
||||
|
|
@ -141,6 +177,17 @@
|
|||
#define VPU_37XX_HOST_IF_TBU_MMUSSIDV_TBU4_AWMMUSSIDV_MASK BIT_MASK(8)
|
||||
#define VPU_37XX_HOST_IF_TBU_MMUSSIDV_TBU4_ARMMUSSIDV_MASK BIT_MASK(9)
|
||||
|
||||
#define VPU_40XX_CPU_SS_CPR_NOC_QREQN 0x01010030u
|
||||
#define VPU_40XX_CPU_SS_CPR_NOC_QREQN_TOP_MMIO_MASK BIT_MASK(0)
|
||||
|
||||
#define VPU_40XX_CPU_SS_CPR_NOC_QACCEPTN 0x01010034u
|
||||
#define VPU_40XX_CPU_SS_CPR_NOC_QACCEPTN_TOP_MMIO_MASK BIT_MASK(0)
|
||||
|
||||
#define VPU_40XX_CPU_SS_CPR_NOC_QDENY 0x01010038u
|
||||
#define VPU_40XX_CPU_SS_CPR_NOC_QDENY_TOP_MMIO_MASK BIT_MASK(0)
|
||||
|
||||
#define VPU_40XX_CPU_SS_TIM_PERF_EXT_FREE_CNT 0x01029008u
|
||||
|
||||
#define VPU_37XX_CPU_SS_DSU_LEON_RT_BASE 0x04000000u
|
||||
#define VPU_37XX_CPU_SS_DSU_LEON_RT_DSU_CTRL 0x04000000u
|
||||
#define VPU_37XX_CPU_SS_DSU_LEON_RT_PC_REG 0x04400010u
|
||||
|
|
@ -161,18 +208,32 @@
|
|||
#define VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC_IRQI_RSTVEC_MASK GENMASK(31, 4)
|
||||
|
||||
#define VPU_37XX_CPU_SS_TIM_WATCHDOG 0x0602009cu
|
||||
#define VPU_40XX_CPU_SS_TIM_WATCHDOG 0x0102009cu
|
||||
|
||||
#define VPU_37XX_CPU_SS_TIM_WDOG_EN 0x060200a4u
|
||||
#define VPU_40XX_CPU_SS_TIM_WDOG_EN 0x010200a4u
|
||||
|
||||
#define VPU_37XX_CPU_SS_TIM_SAFE 0x060200a8u
|
||||
#define VPU_40XX_CPU_SS_TIM_SAFE 0x010200a8u
|
||||
|
||||
#define VPU_37XX_CPU_SS_TIM_IPC_FIFO 0x060200f0u
|
||||
#define VPU_40XX_CPU_SS_TIM_IPC_FIFO 0x010200f0u
|
||||
|
||||
#define VPU_37XX_CPU_SS_TIM_GEN_CONFIG 0x06021008u
|
||||
#define VPU_37XX_CPU_SS_TIM_GEN_CONFIG_WDOG_TO_INT_CLR_MASK BIT_MASK(9)
|
||||
|
||||
#define VPU_40XX_CPU_SS_TIM_GEN_CONFIG 0x01021008u
|
||||
#define VPU_40XX_CPU_SS_TIM_GEN_CONFIG_WDOG_TO_INT_CLR_MASK BIT_MASK(9)
|
||||
|
||||
#define VPU_37XX_CPU_SS_TIM_PERF_FREE_CNT 0x06029000u
|
||||
|
||||
#define VPU_37XX_CPU_SS_DOORBELL_0 0x06300000u
|
||||
#define VPU_37XX_CPU_SS_DOORBELL_0_SET_MASK BIT_MASK(0)
|
||||
|
||||
#define VPU_37XX_CPU_SS_DOORBELL_1 0x06301000u
|
||||
#define VPU_40XX_CPU_SS_DOORBELL_0 0x01300000u
|
||||
#define VPU_40XX_CPU_SS_DOORBELL_0_SET_MASK BIT_MASK(0)
|
||||
|
||||
#endif /* __IVPU_HW_37XX_REG_H__ */
|
||||
#define VPU_37XX_CPU_SS_DOORBELL_1 0x06301000u
|
||||
#define VPU_40XX_CPU_SS_DOORBELL_1 0x01301000u
|
||||
|
||||
#endif /* __IVPU_HW_IP_REG_H__ */
|
||||
|
|
@ -46,7 +46,6 @@ static void ivpu_pm_prepare_cold_boot(struct ivpu_device *vdev)
|
|||
ivpu_cmdq_reset_all_contexts(vdev);
|
||||
ivpu_ipc_reset(vdev);
|
||||
ivpu_fw_log_reset(vdev);
|
||||
ivpu_fw_load(vdev);
|
||||
fw->last_heartbeat = 0;
|
||||
|
||||
ivpu_dbg(vdev, FW_BOOT, "Cold boot entry point 0x%llx", vdev->fw->cold_boot_entry_point);
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ MODULE_PARM_DESC(mhi_timeout_ms, "MHI controller timeout value");
|
|||
static const char *fw_image_paths[FAMILY_MAX] = {
|
||||
[FAMILY_AIC100] = "qcom/aic100/sbl.bin",
|
||||
[FAMILY_AIC200] = "qcom/aic200/sbl.bin",
|
||||
[FAMILY_AIC200_VF] = NULL,
|
||||
};
|
||||
|
||||
static const struct mhi_channel_config aic100_channels[] = {
|
||||
|
|
@ -691,6 +692,159 @@ static const struct mhi_channel_config aic200_channels[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static const struct mhi_channel_config aic200vf_channels[] = {
|
||||
{
|
||||
.name = "QAIC_LOOPBACK",
|
||||
.num = 0,
|
||||
.num_elements = 32,
|
||||
.local_elements = 0,
|
||||
.event_ring = 0,
|
||||
.dir = DMA_TO_DEVICE,
|
||||
.ee_mask = MHI_CH_EE_AMSS,
|
||||
.pollcfg = 0,
|
||||
.doorbell = MHI_DB_BRST_DISABLE,
|
||||
.lpm_notify = false,
|
||||
.offload_channel = false,
|
||||
.doorbell_mode_switch = false,
|
||||
.wake_capable = false,
|
||||
},
|
||||
{
|
||||
.name = "QAIC_LOOPBACK",
|
||||
.num = 1,
|
||||
.num_elements = 32,
|
||||
.local_elements = 0,
|
||||
.event_ring = 0,
|
||||
.dir = DMA_FROM_DEVICE,
|
||||
.ee_mask = MHI_CH_EE_AMSS,
|
||||
.pollcfg = 0,
|
||||
.doorbell = MHI_DB_BRST_DISABLE,
|
||||
.lpm_notify = false,
|
||||
.offload_channel = false,
|
||||
.doorbell_mode_switch = false,
|
||||
.wake_capable = false,
|
||||
},
|
||||
{
|
||||
.name = "QAIC_SSR",
|
||||
.num = 6,
|
||||
.num_elements = 32,
|
||||
.local_elements = 0,
|
||||
.event_ring = 0,
|
||||
.dir = DMA_TO_DEVICE,
|
||||
.ee_mask = MHI_CH_EE_AMSS,
|
||||
.pollcfg = 0,
|
||||
.doorbell = MHI_DB_BRST_DISABLE,
|
||||
.lpm_notify = false,
|
||||
.offload_channel = false,
|
||||
.doorbell_mode_switch = false,
|
||||
.wake_capable = false,
|
||||
},
|
||||
{
|
||||
.name = "QAIC_SSR",
|
||||
.num = 7,
|
||||
.num_elements = 32,
|
||||
.local_elements = 0,
|
||||
.event_ring = 0,
|
||||
.dir = DMA_FROM_DEVICE,
|
||||
.ee_mask = MHI_CH_EE_AMSS,
|
||||
.pollcfg = 0,
|
||||
.doorbell = MHI_DB_BRST_DISABLE,
|
||||
.lpm_notify = false,
|
||||
.offload_channel = false,
|
||||
.doorbell_mode_switch = false,
|
||||
.wake_capable = false,
|
||||
},
|
||||
{
|
||||
.name = "QAIC_CONTROL",
|
||||
.num = 10,
|
||||
.num_elements = 128,
|
||||
.local_elements = 0,
|
||||
.event_ring = 0,
|
||||
.dir = DMA_TO_DEVICE,
|
||||
.ee_mask = MHI_CH_EE_AMSS,
|
||||
.pollcfg = 0,
|
||||
.doorbell = MHI_DB_BRST_DISABLE,
|
||||
.lpm_notify = false,
|
||||
.offload_channel = false,
|
||||
.doorbell_mode_switch = false,
|
||||
.wake_capable = false,
|
||||
},
|
||||
{
|
||||
.name = "QAIC_CONTROL",
|
||||
.num = 11,
|
||||
.num_elements = 128,
|
||||
.local_elements = 0,
|
||||
.event_ring = 0,
|
||||
.dir = DMA_FROM_DEVICE,
|
||||
.ee_mask = MHI_CH_EE_AMSS,
|
||||
.pollcfg = 0,
|
||||
.doorbell = MHI_DB_BRST_DISABLE,
|
||||
.lpm_notify = false,
|
||||
.offload_channel = false,
|
||||
.doorbell_mode_switch = false,
|
||||
.wake_capable = false,
|
||||
},
|
||||
{
|
||||
.name = "QAIC_TELEMETRY",
|
||||
.num = 16,
|
||||
.num_elements = 32,
|
||||
.local_elements = 0,
|
||||
.event_ring = 0,
|
||||
.dir = DMA_TO_DEVICE,
|
||||
.ee_mask = MHI_CH_EE_AMSS,
|
||||
.pollcfg = 0,
|
||||
.doorbell = MHI_DB_BRST_DISABLE,
|
||||
.lpm_notify = false,
|
||||
.offload_channel = false,
|
||||
.doorbell_mode_switch = false,
|
||||
.wake_capable = false,
|
||||
},
|
||||
{
|
||||
.name = "QAIC_TELEMETRY",
|
||||
.num = 17,
|
||||
.num_elements = 32,
|
||||
.local_elements = 0,
|
||||
.event_ring = 0,
|
||||
.dir = DMA_FROM_DEVICE,
|
||||
.ee_mask = MHI_CH_EE_AMSS,
|
||||
.pollcfg = 0,
|
||||
.doorbell = MHI_DB_BRST_DISABLE,
|
||||
.lpm_notify = false,
|
||||
.offload_channel = false,
|
||||
.doorbell_mode_switch = false,
|
||||
.wake_capable = false,
|
||||
},
|
||||
{
|
||||
.name = "IPCR",
|
||||
.num = 24,
|
||||
.num_elements = 32,
|
||||
.local_elements = 0,
|
||||
.event_ring = 0,
|
||||
.dir = DMA_TO_DEVICE,
|
||||
.ee_mask = MHI_CH_EE_AMSS,
|
||||
.pollcfg = 0,
|
||||
.doorbell = MHI_DB_BRST_DISABLE,
|
||||
.lpm_notify = false,
|
||||
.offload_channel = false,
|
||||
.doorbell_mode_switch = false,
|
||||
.wake_capable = false,
|
||||
},
|
||||
{
|
||||
.name = "IPCR",
|
||||
.num = 25,
|
||||
.num_elements = 32,
|
||||
.local_elements = 0,
|
||||
.event_ring = 0,
|
||||
.dir = DMA_FROM_DEVICE,
|
||||
.ee_mask = MHI_CH_EE_AMSS,
|
||||
.pollcfg = 0,
|
||||
.doorbell = MHI_DB_BRST_DISABLE,
|
||||
.lpm_notify = false,
|
||||
.offload_channel = false,
|
||||
.doorbell_mode_switch = false,
|
||||
.wake_capable = false,
|
||||
},
|
||||
};
|
||||
|
||||
static struct mhi_event_config aic100_events[] = {
|
||||
{
|
||||
.num_elements = 32,
|
||||
|
|
@ -721,6 +875,21 @@ static struct mhi_event_config aic200_events[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct mhi_event_config aic200vf_events[] = {
|
||||
{
|
||||
.num_elements = 32,
|
||||
.irq_moderation_ms = 0,
|
||||
.irq = 0,
|
||||
.channel = U32_MAX,
|
||||
.priority = 1,
|
||||
.mode = MHI_DB_BRST_DISABLE,
|
||||
.data_type = MHI_ER_CTRL,
|
||||
.hardware_event = false,
|
||||
.client_managed = false,
|
||||
.offload_channel = false,
|
||||
},
|
||||
};
|
||||
|
||||
static struct mhi_controller_config mhi_cntrl_configs[] = {
|
||||
[FAMILY_AIC100] = {
|
||||
.max_channels = 128,
|
||||
|
|
@ -744,6 +913,17 @@ static struct mhi_controller_config mhi_cntrl_configs[] = {
|
|||
.use_bounce_buf = false,
|
||||
.m2_no_db = false,
|
||||
},
|
||||
[FAMILY_AIC200_VF] = {
|
||||
.max_channels = 128,
|
||||
.timeout_ms = 0, /* controlled by mhi_timeout */
|
||||
.buf_len = 0,
|
||||
.num_channels = ARRAY_SIZE(aic200vf_channels),
|
||||
.ch_cfg = aic200vf_channels,
|
||||
.num_events = ARRAY_SIZE(aic200vf_events),
|
||||
.event_cfg = aic200vf_events,
|
||||
.use_bounce_buf = false,
|
||||
.m2_no_db = false,
|
||||
},
|
||||
};
|
||||
|
||||
static int mhi_read_reg(struct mhi_controller *mhi_cntrl, void __iomem *addr, u32 *out)
|
||||
|
|
@ -864,11 +1044,19 @@ struct mhi_controller *qaic_mhi_register_controller(struct pci_dev *pci_dev, voi
|
|||
|
||||
mhi_cntrl->fw_image = fw_image_paths[family];
|
||||
|
||||
if (family == FAMILY_AIC200) {
|
||||
switch (family) {
|
||||
case FAMILY_AIC200:
|
||||
mhi_cntrl->name = "AIC200";
|
||||
mhi_cntrl->seg_len = SZ_512K;
|
||||
} else {
|
||||
break;
|
||||
case FAMILY_AIC200_VF:
|
||||
mhi_cntrl->name = "AIC200_VF";
|
||||
break;
|
||||
case FAMILY_AIC100:
|
||||
mhi_cntrl->name = "AIC100";
|
||||
break;
|
||||
default:
|
||||
mhi_cntrl->name = NULL;
|
||||
}
|
||||
|
||||
/* use latest configured timeout */
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
enum aic_families {
|
||||
FAMILY_AIC100,
|
||||
FAMILY_AIC200,
|
||||
FAMILY_AIC200_VF,
|
||||
FAMILY_MAX,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1840,15 +1840,16 @@ int qaic_perf_stats_bo_ioctl(struct drm_device *dev, void *data, struct drm_file
|
|||
goto free_ent;
|
||||
}
|
||||
bo = to_qaic_bo(obj);
|
||||
ret = mutex_lock_interruptible(&bo->lock);
|
||||
if (ret)
|
||||
goto put_obj;
|
||||
if (!bo->sliced) {
|
||||
drm_gem_object_put(obj);
|
||||
ret = -EINVAL;
|
||||
goto free_ent;
|
||||
goto unlock_bo;
|
||||
}
|
||||
if (bo->dbc->id != args->hdr.dbc_id) {
|
||||
drm_gem_object_put(obj);
|
||||
ret = -EINVAL;
|
||||
goto free_ent;
|
||||
goto unlock_bo;
|
||||
}
|
||||
/*
|
||||
* perf stats ioctl is called before wait ioctl is complete then
|
||||
|
|
@ -1864,7 +1865,12 @@ int qaic_perf_stats_bo_ioctl(struct drm_device *dev, void *data, struct drm_file
|
|||
bo->perf_stats.req_received_ts), 1000);
|
||||
ent[i].queue_level_before = bo->perf_stats.queue_level_before;
|
||||
ent[i].num_queue_element = bo->total_slice_nents;
|
||||
unlock_bo:
|
||||
mutex_unlock(&bo->lock);
|
||||
put_obj:
|
||||
drm_gem_object_put(obj);
|
||||
if (ret)
|
||||
goto free_ent;
|
||||
}
|
||||
|
||||
if (copy_to_user(u64_to_user_ptr(args->data), ent, args->hdr.count * sizeof(*ent)))
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ MODULE_IMPORT_NS("DMA_BUF");
|
|||
#define PCI_DEVICE_ID_QCOM_AIC080 0xa080
|
||||
#define PCI_DEVICE_ID_QCOM_AIC100 0xa100
|
||||
#define PCI_DEVICE_ID_QCOM_AIC200 0xa110
|
||||
#define PCI_DEVICE_ID_QCOM_AIC200VF 0xa111
|
||||
#define QAIC_NAME "qaic"
|
||||
#define QAIC_DESC "Qualcomm Cloud AI Accelerators"
|
||||
#define CNTL_MAJOR 5
|
||||
|
|
@ -78,6 +79,13 @@ static const struct qaic_device_config aic200_config = {
|
|||
.dbc_bar_idx = 2,
|
||||
};
|
||||
|
||||
static const struct qaic_device_config aic200vf_config = {
|
||||
.family = FAMILY_AIC200_VF,
|
||||
.bar_mask = BIT(0) | BIT(1) | BIT(2) | BIT(4),
|
||||
.mhi_bar_idx = 1,
|
||||
.dbc_bar_idx = 2,
|
||||
};
|
||||
|
||||
bool datapath_polling;
|
||||
module_param(datapath_polling, bool, 0400);
|
||||
MODULE_PARM_DESC(datapath_polling, "Operate the datapath in polling mode");
|
||||
|
|
@ -610,6 +618,8 @@ static void qaic_pci_remove(struct pci_dev *pdev)
|
|||
{
|
||||
struct qaic_device *qdev = pci_get_drvdata(pdev);
|
||||
|
||||
pci_disable_sriov(pdev);
|
||||
|
||||
if (!qdev)
|
||||
return;
|
||||
|
||||
|
|
@ -666,6 +676,7 @@ static const struct pci_device_id qaic_ids[] = {
|
|||
{ PCI_DEVICE_DATA(QCOM, AIC080, (kernel_ulong_t)&aic080_config), },
|
||||
{ PCI_DEVICE_DATA(QCOM, AIC100, (kernel_ulong_t)&aic100_config), },
|
||||
{ PCI_DEVICE_DATA(QCOM, AIC200, (kernel_ulong_t)&aic200_config), },
|
||||
{ PCI_DEVICE_DATA(QCOM, AIC200VF, (kernel_ulong_t)&aic200vf_config), },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, qaic_ids);
|
||||
|
|
@ -762,6 +773,41 @@ static const struct dev_pm_ops qaic_pm_ops = {
|
|||
SYSTEM_SLEEP_PM_OPS(qaic_pm_suspend, qaic_pm_resume)
|
||||
};
|
||||
|
||||
static int qaic_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
|
||||
{
|
||||
struct qaic_device *qdev = pci_get_drvdata(pdev);
|
||||
int rcu_id;
|
||||
int ret;
|
||||
|
||||
if (num_vfs == 0) {
|
||||
pci_disable_sriov(pdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rcu_id = srcu_read_lock(&qdev->dev_lock);
|
||||
/* Qaic device must be online to process VF bringup */
|
||||
if (qdev->dev_state == QAIC_OFFLINE) {
|
||||
ret = -ENODEV;
|
||||
goto unlock_dev_srcu;
|
||||
}
|
||||
if (qdev->dev_state == QAIC_BOOT) {
|
||||
ret = -EBUSY;
|
||||
goto unlock_dev_srcu;
|
||||
}
|
||||
|
||||
ret = pci_enable_sriov(pdev, num_vfs);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to enable SR-IOV: %d (requested %d VFs, max %d)\n",
|
||||
ret, num_vfs, pci_sriov_get_totalvfs(pdev));
|
||||
goto unlock_dev_srcu;
|
||||
}
|
||||
|
||||
dev_dbg(&pdev->dev, "Successfully enabled %d VFs\n", num_vfs);
|
||||
unlock_dev_srcu:
|
||||
srcu_read_unlock(&qdev->dev_lock, rcu_id);
|
||||
return ret ?: num_vfs;
|
||||
}
|
||||
|
||||
static struct pci_driver qaic_pci_driver = {
|
||||
.name = QAIC_NAME,
|
||||
.id_table = qaic_ids,
|
||||
|
|
@ -769,6 +815,7 @@ static struct pci_driver qaic_pci_driver = {
|
|||
.remove = qaic_pci_remove,
|
||||
.shutdown = qaic_pci_shutdown,
|
||||
.err_handler = &qaic_pci_err_handler,
|
||||
.sriov_configure = qaic_pci_sriov_configure,
|
||||
.driver = {
|
||||
.pm = pm_sleep_ptr(&qaic_pm_ops),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -881,6 +881,7 @@ static void sahara_mhi_remove(struct mhi_device *mhi_dev)
|
|||
|
||||
cancel_work_sync(&context->fw_work);
|
||||
cancel_work_sync(&context->dump_work);
|
||||
cancel_work_sync(&context->read_data_work);
|
||||
vfree(context->mem_dump);
|
||||
sahara_release_image(context);
|
||||
mhi_unprepare_from_transfer(mhi_dev);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <drm/drm_file.h>
|
||||
#include <drm/drm_gem.h>
|
||||
#include <drm/rocket_accel.h>
|
||||
#include <linux/align.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/iommu.h>
|
||||
|
|
@ -21,6 +22,15 @@
|
|||
|
||||
#define JOB_TIMEOUT_MS 500
|
||||
|
||||
/*
|
||||
* The PC unit fetches two 64-bit register commands per pc_data_amount unit,
|
||||
* and the field holds (regcmd_count + 1) / 2 - 1.
|
||||
*/
|
||||
#define ROCKET_MAX_REGCMDS ((PC_REGISTER_AMOUNTS_PC_DATA_AMOUNT__MASK + 1) * 2U)
|
||||
|
||||
/* Bits 3:0 of PC_BASE_ADDRESS hold the mode selection bit and reserved bits */
|
||||
#define ROCKET_REGCMD_ALIGN 16
|
||||
|
||||
static struct rocket_job *
|
||||
to_rocket_job(struct drm_sched_job *sched_job)
|
||||
{
|
||||
|
|
@ -78,7 +88,7 @@ rocket_copy_tasks(struct drm_device *dev,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (int i = 0; i < rjob->task_count; i++) {
|
||||
for (unsigned int i = 0; i < rjob->task_count; i++) {
|
||||
struct drm_rocket_task task = {0};
|
||||
|
||||
if (copy_from_user(&task,
|
||||
|
|
@ -95,6 +105,20 @@ rocket_copy_tasks(struct drm_device *dev,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (task.regcmd_count > ROCKET_MAX_REGCMDS) {
|
||||
drm_dbg(dev, "regcmd_count field in drm_rocket_task should be <= %u.\n",
|
||||
ROCKET_MAX_REGCMDS);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!IS_ALIGNED(task.regcmd, ROCKET_REGCMD_ALIGN)) {
|
||||
drm_dbg(dev, "regcmd field in drm_rocket_task should be aligned to %u bytes.\n",
|
||||
ROCKET_REGCMD_ALIGN);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rjob->tasks[i].regcmd = task.regcmd;
|
||||
rjob->tasks[i].regcmd_count = task.regcmd_count;
|
||||
}
|
||||
|
|
@ -494,8 +518,6 @@ int rocket_job_init(struct rocket_core *core)
|
|||
return 0;
|
||||
|
||||
err_sched:
|
||||
drm_sched_fini(&core->sched);
|
||||
|
||||
destroy_workqueue(core->reset.wq);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -370,6 +370,15 @@ static void test_unwrap_merge_seqno(struct kunit *test)
|
|||
dma_fence_put(f1);
|
||||
}
|
||||
|
||||
static void test_dedup_empty(struct kunit *test)
|
||||
{
|
||||
struct dma_fence *fence[1] = { NULL };
|
||||
int ret;
|
||||
|
||||
ret = dma_fence_dedup_array(fence, 0);
|
||||
KUNIT_EXPECT_EQ(test, ret, 0);
|
||||
}
|
||||
|
||||
static void test_unwrap_merge_order(struct kunit *test)
|
||||
{
|
||||
struct dma_fence *fence, *f1, *f2, *a1, *a2, *c1, *c2;
|
||||
|
|
@ -595,6 +604,7 @@ static struct kunit_case dma_fence_unwrap_cases[] = {
|
|||
KUNIT_CASE(test_unwrap_merge_order),
|
||||
KUNIT_CASE(test_unwrap_merge_complex),
|
||||
KUNIT_CASE(test_unwrap_merge_complex_seqno),
|
||||
KUNIT_CASE(test_dedup_empty),
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2148,7 +2148,6 @@ EXPORT_SYMBOL(gpu_buddy_block_print);
|
|||
* gpu_buddy_print - print allocator state
|
||||
*
|
||||
* @mm: GPU buddy manager
|
||||
* @p: GPU printer to use
|
||||
*/
|
||||
void gpu_buddy_print(struct gpu_buddy *mm)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ static void komeda_wb_connector_destroy(struct drm_connector *connector)
|
|||
}
|
||||
|
||||
static const struct drm_connector_funcs komeda_wb_connector_funcs = {
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.atomic_create_state = drm_atomic_helper_connector_create_state,
|
||||
.detect = komeda_wb_connector_detect,
|
||||
.fill_modes = komeda_wb_connector_fill_modes,
|
||||
.destroy = komeda_wb_connector_destroy,
|
||||
|
|
|
|||
|
|
@ -64,18 +64,18 @@ static const struct drm_connector_helper_funcs malidp_mw_connector_helper_funcs
|
|||
.mode_valid = malidp_mw_connector_mode_valid,
|
||||
};
|
||||
|
||||
static void malidp_mw_connector_reset(struct drm_connector *connector)
|
||||
static struct drm_connector_state *
|
||||
malidp_mw_connector_create_state(struct drm_connector *connector)
|
||||
{
|
||||
struct malidp_mw_connector_state *mw_state = kzalloc_obj(*mw_state);
|
||||
struct malidp_mw_connector_state *mw_state;
|
||||
|
||||
if (connector->state)
|
||||
__drm_atomic_helper_connector_destroy_state(connector->state);
|
||||
mw_state = kzalloc_obj(*mw_state);
|
||||
if (!mw_state)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
kfree(connector->state);
|
||||
connector->state = NULL;
|
||||
__drm_atomic_helper_connector_state_init(&mw_state->base, connector);
|
||||
|
||||
if (mw_state)
|
||||
__drm_atomic_helper_connector_reset(connector, &mw_state->base);
|
||||
return &mw_state->base;
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
|
|
@ -111,7 +111,7 @@ malidp_mw_connector_duplicate_state(struct drm_connector *connector)
|
|||
}
|
||||
|
||||
static const struct drm_connector_funcs malidp_mw_connector_funcs = {
|
||||
.reset = malidp_mw_connector_reset,
|
||||
.atomic_create_state = malidp_mw_connector_create_state,
|
||||
.detect = malidp_mw_connector_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = malidp_mw_connector_destroy,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/hdmi.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -775,11 +776,6 @@ static int adv7511_connector_init(struct adv7511 *adv)
|
|||
* DRM Bridge Operations
|
||||
*/
|
||||
|
||||
static const struct adv7511 *bridge_to_adv7511_const(const struct drm_bridge *bridge)
|
||||
{
|
||||
return container_of(bridge, struct adv7511, bridge);
|
||||
}
|
||||
|
||||
static void adv7511_bridge_atomic_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *state)
|
||||
{
|
||||
|
|
@ -817,19 +813,6 @@ static void adv7511_bridge_atomic_disable(struct drm_bridge *bridge,
|
|||
adv7511_power_off(adv);
|
||||
}
|
||||
|
||||
static enum drm_mode_status
|
||||
adv7511_bridge_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
|
||||
const struct drm_display_mode *mode,
|
||||
unsigned long long tmds_rate)
|
||||
{
|
||||
const struct adv7511 *adv = bridge_to_adv7511_const(bridge);
|
||||
|
||||
if (tmds_rate > 1000ULL * adv->info->max_mode_clock_khz)
|
||||
return MODE_CLOCK_HIGH;
|
||||
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static enum drm_mode_status adv7511_bridge_mode_valid(struct drm_bridge *bridge,
|
||||
const struct drm_display_info *info,
|
||||
const struct drm_display_mode *mode)
|
||||
|
|
@ -1006,7 +989,6 @@ static const struct drm_bridge_funcs adv7511_bridge_funcs = {
|
|||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
|
||||
.hdmi_tmds_char_rate_valid = adv7511_bridge_hdmi_tmds_char_rate_valid,
|
||||
.hdmi_clear_audio_infoframe = adv7511_bridge_hdmi_clear_audio_infoframe,
|
||||
.hdmi_write_audio_infoframe = adv7511_bridge_hdmi_write_audio_infoframe,
|
||||
.hdmi_clear_avi_infoframe = adv7511_bridge_hdmi_clear_avi_infoframe,
|
||||
|
|
@ -1359,6 +1341,8 @@ static int adv7511_probe(struct i2c_client *i2c)
|
|||
|
||||
adv7511->bridge.vendor = "Analog";
|
||||
adv7511->bridge.product = adv7511->info->name;
|
||||
adv7511->bridge.supported_hdmi_ver = HDMI_VERSION_1_2;
|
||||
adv7511->bridge.max_tmds_char_rate = 1000ULL * adv7511->info->max_mode_clock_khz;
|
||||
|
||||
#ifdef CONFIG_DRM_I2C_ADV7511_AUDIO
|
||||
adv7511->bridge.ops |= DRM_BRIDGE_OP_HDMI_AUDIO;
|
||||
|
|
|
|||
|
|
@ -1119,6 +1119,7 @@ struct inno_hdmi *inno_hdmi_bind(struct device *dev,
|
|||
hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
|
||||
hdmi->bridge.vendor = "Inno";
|
||||
hdmi->bridge.product = "Inno HDMI";
|
||||
hdmi->bridge.supported_hdmi_ver = HDMI_VERSION_1_2;
|
||||
|
||||
hdmi->bridge.ddc = inno_hdmi_i2c_adapter(hdmi);
|
||||
if (IS_ERR(hdmi->bridge.ddc))
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <drm/display/drm_hdmi_helper.h>
|
||||
#include <drm/display/drm_hdmi_state_helper.h>
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
|
|
@ -669,20 +668,6 @@ static void it6263_bridge_atomic_enable(struct drm_bridge *bridge,
|
|||
regmap_write(regmap, HDMI_REG_PKT_GENERAL_CTRL, ENABLE_PKT | REPEAT_PKT);
|
||||
}
|
||||
|
||||
static enum drm_mode_status
|
||||
it6263_bridge_mode_valid(struct drm_bridge *bridge,
|
||||
const struct drm_display_info *info,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
unsigned long long rate;
|
||||
|
||||
rate = drm_hdmi_compute_mode_clock(mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444);
|
||||
if (rate == 0)
|
||||
return MODE_NOCLOCK;
|
||||
|
||||
return bridge->funcs->hdmi_tmds_char_rate_valid(bridge, mode, rate);
|
||||
}
|
||||
|
||||
static int it6263_bridge_attach(struct drm_bridge *bridge,
|
||||
struct drm_encoder *encoder,
|
||||
enum drm_bridge_attach_flags flags)
|
||||
|
|
@ -753,20 +738,6 @@ it6263_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
|
|||
return input_fmts;
|
||||
}
|
||||
|
||||
static enum drm_mode_status
|
||||
it6263_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
|
||||
const struct drm_display_mode *mode,
|
||||
unsigned long long tmds_rate)
|
||||
{
|
||||
if (mode->clock > MAX_PIXEL_CLOCK_KHZ)
|
||||
return MODE_CLOCK_HIGH;
|
||||
|
||||
if (tmds_rate > MAX_HDMI_TMDS_CHAR_RATE_HZ)
|
||||
return MODE_CLOCK_HIGH;
|
||||
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static int it6263_hdmi_clear_avi_infoframe(struct drm_bridge *bridge)
|
||||
{
|
||||
struct it6263 *it = bridge_to_it6263(bridge);
|
||||
|
|
@ -831,13 +802,11 @@ static const struct drm_bridge_funcs it6263_bridge_funcs = {
|
|||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.attach = it6263_bridge_attach,
|
||||
.mode_valid = it6263_bridge_mode_valid,
|
||||
.atomic_disable = it6263_bridge_atomic_disable,
|
||||
.atomic_enable = it6263_bridge_atomic_enable,
|
||||
.detect = it6263_bridge_detect,
|
||||
.edid_read = it6263_bridge_edid_read,
|
||||
.atomic_get_input_bus_fmts = it6263_bridge_atomic_get_input_bus_fmts,
|
||||
.hdmi_tmds_char_rate_valid = it6263_hdmi_tmds_char_rate_valid,
|
||||
.hdmi_clear_avi_infoframe = it6263_hdmi_clear_avi_infoframe,
|
||||
.hdmi_write_avi_infoframe = it6263_hdmi_write_avi_infoframe,
|
||||
.hdmi_clear_hdmi_infoframe = it6263_hdmi_clear_hdmi_infoframe,
|
||||
|
|
@ -899,6 +868,8 @@ static int it6263_probe(struct i2c_client *client)
|
|||
it->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
|
||||
it->bridge.vendor = "ITE";
|
||||
it->bridge.product = "IT6263";
|
||||
it->bridge.supported_hdmi_ver = HDMI_VERSION_1_3;
|
||||
it->bridge.max_tmds_char_rate = 1000ULL * MAX_PIXEL_CLOCK_KHZ;
|
||||
|
||||
return devm_drm_bridge_add(dev, &it->bridge);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/media-bus-format.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/hdmi.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/bitfield.h>
|
||||
|
|
@ -867,15 +868,6 @@ it66121_bridge_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
|
|||
const struct drm_display_mode *mode,
|
||||
unsigned long long tmds_rate)
|
||||
{
|
||||
const struct it66121_ctx *ctx =
|
||||
container_of(bridge, const struct it66121_ctx, bridge);
|
||||
unsigned long long max_rate;
|
||||
|
||||
max_rate = (ctx->bus_width == 12) ? 74250000ULL : 148500000ULL;
|
||||
|
||||
if (tmds_rate > max_rate)
|
||||
return MODE_CLOCK_HIGH;
|
||||
|
||||
if (tmds_rate < HDMI_TMDS_CHAR_RATE_MIN_HZ)
|
||||
return MODE_CLOCK_LOW;
|
||||
|
||||
|
|
@ -1670,6 +1662,9 @@ static int it66121_probe(struct i2c_client *client)
|
|||
DRM_BRIDGE_OP_HDMI;
|
||||
ctx->bridge.vendor = "ITE";
|
||||
ctx->bridge.product = "IT66121";
|
||||
ctx->bridge.supported_hdmi_ver = HDMI_VERSION_1_2;
|
||||
ctx->bridge.max_tmds_char_rate = ctx->bus_width == 12 ? 74250000ULL : 148500000ULL;
|
||||
|
||||
if (client->irq > 0) {
|
||||
ctx->bridge.ops |= DRM_BRIDGE_OP_HPD;
|
||||
|
||||
|
|
|
|||
|
|
@ -554,7 +554,6 @@ static int lt8713sx_probe(struct i2c_client *client)
|
|||
|
||||
lt8713sx_reset(lt8713sx);
|
||||
|
||||
lt8713sx->bridge.funcs = <8713sx_bridge_funcs;
|
||||
lt8713sx->bridge.of_node = dev->of_node;
|
||||
lt8713sx->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
|
||||
drm_bridge_add(<8713sx->bridge);
|
||||
|
|
|
|||
|
|
@ -416,7 +416,7 @@ static const struct drm_connector_funcs lt8912_connector_funcs = {
|
|||
.detect = lt8912_connector_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = drm_connector_cleanup,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.atomic_create_state = drm_atomic_helper_connector_create_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/hdmi.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/media-bus-format.h>
|
||||
|
|
@ -952,18 +953,6 @@ static int lt9611_hdmi_write_hdmi_infoframe(struct drm_bridge *bridge,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static enum drm_mode_status
|
||||
lt9611_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
|
||||
const struct drm_display_mode *mode,
|
||||
unsigned long long tmds_rate)
|
||||
{
|
||||
/* 297 MHz for 4k@30 mode */
|
||||
if (tmds_rate > 297000000)
|
||||
return MODE_CLOCK_HIGH;
|
||||
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static int lt9611_hdmi_audio_startup(struct drm_bridge *bridge,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
|
|
@ -1029,7 +1018,6 @@ static const struct drm_bridge_funcs lt9611_bridge_funcs = {
|
|||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_get_input_bus_fmts = lt9611_atomic_get_input_bus_fmts,
|
||||
|
||||
.hdmi_tmds_char_rate_valid = lt9611_hdmi_tmds_char_rate_valid,
|
||||
.hdmi_write_audio_infoframe = lt9611_hdmi_write_audio_infoframe,
|
||||
.hdmi_clear_audio_infoframe = lt9611_hdmi_clear_audio_infoframe,
|
||||
.hdmi_write_avi_infoframe = lt9611_hdmi_write_avi_infoframe,
|
||||
|
|
@ -1175,6 +1163,8 @@ static int lt9611_probe(struct i2c_client *client)
|
|||
lt9611->bridge.hdmi_audio_dev = dev;
|
||||
lt9611->bridge.hdmi_audio_max_i2s_playback_channels = 8;
|
||||
lt9611->bridge.hdmi_audio_dai_port = 2;
|
||||
lt9611->bridge.supported_hdmi_ver = HDMI_VERSION_1_4;
|
||||
lt9611->bridge.max_tmds_char_rate = 297000000; /* 297 MHz for 4k@30 mode */
|
||||
|
||||
drm_bridge_add(<9611->bridge);
|
||||
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ static const struct drm_connector_funcs ge_b850v3_lvds_connector_funcs = {
|
|||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.detect = ge_b850v3_lvds_detect,
|
||||
.destroy = drm_connector_cleanup,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.atomic_create_state = drm_atomic_helper_connector_create_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -275,6 +275,11 @@ static const struct of_device_id simple_bridge_match[] = {
|
|||
.data = &(const struct simple_bridge_info) {
|
||||
.connector_type = DRM_MODE_CONNECTOR_HDMIA,
|
||||
},
|
||||
}, {
|
||||
.compatible = "chrontel,ch7218a",
|
||||
.data = &(const struct simple_bridge_info) {
|
||||
.connector_type = DRM_MODE_CONNECTOR_HDMIA,
|
||||
},
|
||||
}, {
|
||||
.compatible = "mstar,tsumu88adt3-lf-1",
|
||||
.data = &(const struct simple_bridge_info) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd.
|
||||
* Copyright (c) 2024 Collabora Ltd.
|
||||
* Copyright (c) 2025 Amazon.com, Inc. or its affiliates.
|
||||
*
|
||||
* Author: Algea Cao <algea.cao@rock-chips.com>
|
||||
* Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
||||
|
|
@ -15,7 +16,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <drm/bridge/dw_hdmi_qp.h>
|
||||
#include <drm/display/drm_hdmi_helper.h>
|
||||
|
|
@ -28,6 +28,7 @@
|
|||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_modes.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
||||
#include <media/cec.h>
|
||||
|
||||
|
|
@ -38,8 +39,6 @@
|
|||
#define DDC_CI_ADDR 0x37
|
||||
#define DDC_SEGMENT_ADDR 0x30
|
||||
|
||||
#define SCRAMB_POLL_DELAY_MS 3000
|
||||
|
||||
struct dw_hdmi_qp_i2c {
|
||||
struct i2c_adapter adap;
|
||||
|
||||
|
|
@ -83,6 +82,9 @@ struct dw_hdmi_qp {
|
|||
struct regmap *regm;
|
||||
int main_irq;
|
||||
|
||||
/* Guards curr_conn between atomic hooks and HPD notify readers */
|
||||
struct mutex mutex;
|
||||
struct drm_connector *curr_conn;
|
||||
unsigned long tmds_char_rate;
|
||||
bool no_hpd;
|
||||
};
|
||||
|
|
@ -350,22 +352,14 @@ static int dw_hdmi_qp_i2c_read(struct dw_hdmi_qp *hdmi,
|
|||
|
||||
stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10);
|
||||
if (!stat) {
|
||||
if (hdmi->no_hpd)
|
||||
dev_dbg_ratelimited(hdmi->dev,
|
||||
"i2c read timed out\n");
|
||||
else
|
||||
dev_err(hdmi->dev, "i2c read timed out\n");
|
||||
dev_dbg_ratelimited(hdmi->dev, "i2c read timed out\n");
|
||||
dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/* Check for error condition on the bus */
|
||||
if (i2c->stat & I2CM_NACK_RCVD_IRQ) {
|
||||
if (hdmi->no_hpd)
|
||||
dev_dbg_ratelimited(hdmi->dev,
|
||||
"i2c read error\n");
|
||||
else
|
||||
dev_err(hdmi->dev, "i2c read error\n");
|
||||
dev_dbg_ratelimited(hdmi->dev, "i2c read error\n");
|
||||
dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);
|
||||
return -EIO;
|
||||
}
|
||||
|
|
@ -404,14 +398,14 @@ static int dw_hdmi_qp_i2c_write(struct dw_hdmi_qp *hdmi,
|
|||
|
||||
stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10);
|
||||
if (!stat) {
|
||||
dev_err(hdmi->dev, "i2c write time out!\n");
|
||||
dev_dbg_ratelimited(hdmi->dev, "i2c write time out!\n");
|
||||
dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/* Check for error condition on the bus */
|
||||
if (i2c->stat & I2CM_NACK_RCVD_IRQ) {
|
||||
dev_err(hdmi->dev, "i2c write nack!\n");
|
||||
dev_dbg_ratelimited(hdmi->dev, "i2c write nack!\n");
|
||||
dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);
|
||||
return -EIO;
|
||||
}
|
||||
|
|
@ -547,6 +541,7 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
|
|||
struct drm_connector_state *conn_state;
|
||||
struct drm_connector *connector;
|
||||
unsigned int op_mode;
|
||||
int ret;
|
||||
|
||||
connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
|
||||
if (WARN_ON(!connector))
|
||||
|
|
@ -557,16 +552,26 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
|
|||
return;
|
||||
|
||||
if (connector->display_info.is_hdmi) {
|
||||
dev_dbg(hdmi->dev, "%s mode=HDMI %s rate=%llu bpc=%u\n", __func__,
|
||||
drm_hdmi_connector_get_output_format_name(conn_state->hdmi.output_format),
|
||||
conn_state->hdmi.tmds_char_rate, conn_state->hdmi.output_bpc);
|
||||
op_mode = 0;
|
||||
hdmi->tmds_char_rate = conn_state->hdmi.tmds_char_rate;
|
||||
|
||||
ret = drm_connector_hdmi_enable_scrambling(connector, conn_state);
|
||||
if (ret)
|
||||
dev_warn(hdmi->dev, "Failed to enable scrambling: %d\n", ret);
|
||||
|
||||
dev_dbg(hdmi->dev, "%s mode=HDMI %s rate=%llu bpc=%u scramb=%d\n", __func__,
|
||||
drm_hdmi_connector_get_output_format_name(conn_state->hdmi.output_format),
|
||||
conn_state->hdmi.tmds_char_rate, conn_state->hdmi.output_bpc,
|
||||
connector->hdmi.scrambler_enabled);
|
||||
} else {
|
||||
dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__);
|
||||
op_mode = OPMODE_DVI;
|
||||
dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__);
|
||||
}
|
||||
|
||||
drm_connector_get(connector);
|
||||
scoped_guard(mutex, &hdmi->mutex)
|
||||
hdmi->curr_conn = connector;
|
||||
|
||||
hdmi->phy.ops->init(hdmi, hdmi->phy.data);
|
||||
|
||||
dw_hdmi_qp_mod(hdmi, HDCP2_BYPASS, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0);
|
||||
|
|
@ -579,9 +584,20 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
|
|||
struct drm_atomic_commit *state)
|
||||
{
|
||||
struct dw_hdmi_qp *hdmi = bridge->driver_private;
|
||||
struct drm_connector *connector;
|
||||
|
||||
scoped_guard(mutex, &hdmi->mutex) {
|
||||
if (hdmi->curr_conn) {
|
||||
drm_connector_put(hdmi->curr_conn);
|
||||
hdmi->curr_conn = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
hdmi->tmds_char_rate = 0;
|
||||
|
||||
connector = drm_atomic_get_old_connector_for_encoder(state, bridge->encoder);
|
||||
drm_connector_hdmi_disable_scrambling(connector);
|
||||
|
||||
hdmi->phy.ops->disable(hdmi, hdmi->phy.data);
|
||||
}
|
||||
|
||||
|
|
@ -616,24 +632,24 @@ dw_hdmi_qp_bridge_edid_read(struct drm_bridge *bridge,
|
|||
return drm_edid;
|
||||
}
|
||||
|
||||
static enum drm_mode_status
|
||||
dw_hdmi_qp_bridge_tmds_char_rate_valid(const struct drm_bridge *bridge,
|
||||
const struct drm_display_mode *mode,
|
||||
unsigned long long rate)
|
||||
static int dw_hdmi_qp_bridge_scrambler_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct dw_hdmi_qp *hdmi = bridge->driver_private;
|
||||
|
||||
/*
|
||||
* TODO: when hdmi->no_hpd is 1 we must not support modes that
|
||||
* require scrambling, including every mode with a clock above
|
||||
* HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ.
|
||||
*/
|
||||
if (rate > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ) {
|
||||
dev_dbg(hdmi->dev, "Unsupported TMDS char rate: %lld\n", rate);
|
||||
return MODE_CLOCK_HIGH;
|
||||
}
|
||||
dw_hdmi_qp_write(hdmi, 1, SCRAMB_CONFIG0);
|
||||
dev_dbg(hdmi->dev, "scrambler enabled\n");
|
||||
|
||||
return MODE_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_hdmi_qp_bridge_scrambler_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct dw_hdmi_qp *hdmi = bridge->driver_private;
|
||||
|
||||
dw_hdmi_qp_write(hdmi, 0, SCRAMB_CONFIG0);
|
||||
dev_dbg(hdmi->dev, "scrambler disabled\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_hdmi_qp_bridge_clear_avi_infoframe(struct drm_bridge *bridge)
|
||||
|
|
@ -982,6 +998,22 @@ static int dw_hdmi_qp_cec_transmit(struct drm_bridge *bridge, u8 attempts,
|
|||
#define dw_hdmi_qp_cec_transmit NULL
|
||||
#endif /* CONFIG_DRM_DW_HDMI_QP_CEC */
|
||||
|
||||
static void dw_hdmi_qp_bridge_hpd_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct dw_hdmi_qp *hdmi = bridge->driver_private;
|
||||
|
||||
if (hdmi->phy.ops->enable_hpd)
|
||||
hdmi->phy.ops->enable_hpd(hdmi, hdmi->phy.data);
|
||||
}
|
||||
|
||||
static void dw_hdmi_qp_bridge_hpd_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct dw_hdmi_qp *hdmi = bridge->driver_private;
|
||||
|
||||
if (hdmi->phy.ops->disable_hpd)
|
||||
hdmi->phy.ops->disable_hpd(hdmi, hdmi->phy.data);
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
|
||||
.atomic_get_output_bus_fmts = drm_atomic_helper_bridge_get_hdmi_output_bus_fmts,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
|
|
@ -990,8 +1022,11 @@ static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
|
|||
.atomic_enable = dw_hdmi_qp_bridge_atomic_enable,
|
||||
.atomic_disable = dw_hdmi_qp_bridge_atomic_disable,
|
||||
.detect = dw_hdmi_qp_bridge_detect,
|
||||
.hpd_enable = dw_hdmi_qp_bridge_hpd_enable,
|
||||
.hpd_disable = dw_hdmi_qp_bridge_hpd_disable,
|
||||
.edid_read = dw_hdmi_qp_bridge_edid_read,
|
||||
.hdmi_tmds_char_rate_valid = dw_hdmi_qp_bridge_tmds_char_rate_valid,
|
||||
.hdmi_scrambler_enable = dw_hdmi_qp_bridge_scrambler_enable,
|
||||
.hdmi_scrambler_disable = dw_hdmi_qp_bridge_scrambler_disable,
|
||||
.hdmi_clear_avi_infoframe = dw_hdmi_qp_bridge_clear_avi_infoframe,
|
||||
.hdmi_write_avi_infoframe = dw_hdmi_qp_bridge_write_avi_infoframe,
|
||||
.hdmi_clear_hdmi_infoframe = dw_hdmi_qp_bridge_clear_hdmi_infoframe,
|
||||
|
|
@ -1054,9 +1089,6 @@ static void dw_hdmi_qp_init_hw(struct dw_hdmi_qp *hdmi)
|
|||
/* Clear DONE and ERROR interrupts */
|
||||
dw_hdmi_qp_write(hdmi, I2CM_OP_DONE_CLEAR | I2CM_NACK_RCVD_CLEAR,
|
||||
MAINUNIT_1_INT_CLEAR);
|
||||
|
||||
if (hdmi->phy.ops->setup_hpd)
|
||||
hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data);
|
||||
}
|
||||
|
||||
struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
|
||||
|
|
@ -1079,6 +1111,10 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
|
|||
if (IS_ERR(hdmi))
|
||||
return ERR_CAST(hdmi);
|
||||
|
||||
ret = devm_mutex_init(dev, &hdmi->mutex);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
hdmi->dev = dev;
|
||||
|
||||
regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
|
|
@ -1119,13 +1155,18 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
|
|||
DRM_BRIDGE_OP_HDMI_AUDIO |
|
||||
DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME |
|
||||
DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME;
|
||||
if (!hdmi->no_hpd)
|
||||
hdmi->bridge.ops |= DRM_BRIDGE_OP_HPD;
|
||||
hdmi->bridge.of_node = pdev->dev.of_node;
|
||||
hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
|
||||
hdmi->bridge.vendor = "Synopsys";
|
||||
hdmi->bridge.product = "DW HDMI QP TX";
|
||||
|
||||
if (hdmi->no_hpd) {
|
||||
hdmi->bridge.supported_hdmi_ver = HDMI_VERSION_1_4;
|
||||
} else {
|
||||
hdmi->bridge.supported_hdmi_ver = HDMI_VERSION_2_0;
|
||||
hdmi->bridge.ops |= DRM_BRIDGE_OP_HPD;
|
||||
}
|
||||
|
||||
if (plat_data->supported_formats)
|
||||
hdmi->bridge.supported_formats = plat_data->supported_formats;
|
||||
|
||||
|
|
@ -1169,6 +1210,46 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(dw_hdmi_qp_bind);
|
||||
|
||||
/**
|
||||
* dw_hdmi_qp_hpd_notify() - Notify a hot-plug detection event
|
||||
* @hdmi: pointer to the DW HDMI QP controller
|
||||
*
|
||||
* Platform drivers should call this from their threaded IRQ handler or work
|
||||
* function to notify the bridge of a connection status change.
|
||||
* The bridge's .read_hpd() phy_ops callback is used to read the current
|
||||
* connection status.
|
||||
*/
|
||||
void dw_hdmi_qp_hpd_notify(struct dw_hdmi_qp *hdmi)
|
||||
{
|
||||
enum drm_connector_status status;
|
||||
struct drm_connector *conn;
|
||||
|
||||
scoped_guard(mutex, &hdmi->mutex) {
|
||||
conn = hdmi->curr_conn;
|
||||
if (conn)
|
||||
drm_connector_get(conn);
|
||||
}
|
||||
|
||||
status = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data);
|
||||
dev_dbg(hdmi->dev, "%s status=%d\n", __func__, status);
|
||||
|
||||
/*
|
||||
* When the display pipeline has been already active, switch to
|
||||
* drm_connector_helper_hpd_irq_event() to ensure .detect_ctx()
|
||||
* gets invoked, i.e. via drm_helper_probe_detect(), because
|
||||
* drm_bridge_hpd_notify() defers to a delayed hotplug path in
|
||||
* this case.
|
||||
*/
|
||||
if (conn && status == connector_status_connected)
|
||||
drm_connector_helper_hpd_irq_event(conn);
|
||||
else
|
||||
drm_bridge_hpd_notify(&hdmi->bridge, status);
|
||||
|
||||
if (conn)
|
||||
drm_connector_put(conn);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_hdmi_qp_hpd_notify);
|
||||
|
||||
void dw_hdmi_qp_suspend(struct device *dev, struct dw_hdmi_qp *hdmi)
|
||||
{
|
||||
disable_irq(hdmi->main_irq);
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ static const struct drm_connector_helper_funcs hv_drm_connector_helper_funcs = {
|
|||
static const struct drm_connector_funcs hv_drm_connector_funcs = {
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = drm_connector_cleanup,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.atomic_create_state = drm_atomic_helper_connector_create_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -314,7 +314,7 @@ static void imx_tve_connector_destroy(struct drm_connector *connector)
|
|||
static const struct drm_connector_funcs imx_tve_connector_funcs = {
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = imx_tve_connector_destroy,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.atomic_create_state = drm_atomic_helper_connector_create_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -306,7 +306,7 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
|
|||
getparam->value = 1;
|
||||
break;
|
||||
case NOUVEAU_GETPARAM_GRAPH_UNITS:
|
||||
getparam->value = nvkm_gr_units(gr);
|
||||
getparam->value = gr ? nvkm_gr_units(gr) : 0;
|
||||
break;
|
||||
case NOUVEAU_GETPARAM_EXEC_PUSH_MAX: {
|
||||
int ib_max = getparam_dma_ib_max(device);
|
||||
|
|
|
|||
|
|
@ -695,6 +695,8 @@ config DRM_PANEL_NOVATEK_NT36536
|
|||
depends on OF
|
||||
depends on DRM_MIPI_DSI
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
select DRM_DISPLAY_DSC_HELPER
|
||||
select DRM_DISPLAY_HELPER
|
||||
select DRM_KMS_HELPER
|
||||
help
|
||||
Say Y here if you want to enable support for Novatek NT36536-based
|
||||
|
|
@ -753,6 +755,15 @@ config DRM_PANEL_NOVATEK_NT39016
|
|||
Say Y here if you want to enable support for the panels built
|
||||
around the Novatek NT39016 display controller.
|
||||
|
||||
config DRM_PANEL_NOVATEK_NT51021
|
||||
tristate "Novatek NT51021 DSI panel"
|
||||
depends on OF
|
||||
depends on DRM_MIPI_DSI
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
help
|
||||
Say Y here if you want to enable support for the panels built
|
||||
around the Novatek NT51021 Display controller.
|
||||
|
||||
config DRM_PANEL_OLIMEX_LCD_OLINUXINO
|
||||
tristate "Olimex LCD-OLinuXino panel"
|
||||
depends on OF
|
||||
|
|
@ -850,6 +861,21 @@ config DRM_PANEL_RAYDIUM_RM692E5
|
|||
Say Y here if you want to enable support for Raydium RM692E5-based
|
||||
display panels, such as the one found in the Fairphone 5 smartphone.
|
||||
|
||||
config DRM_PANEL_RAYDIUM_RM69220
|
||||
tristate "Raydium RM69220-based DSI panel"
|
||||
depends on OF
|
||||
depends on DRM_MIPI_DSI
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
select DRM_DISPLAY_DSC_HELPER
|
||||
select DRM_DISPLAY_HELPER
|
||||
help
|
||||
Say Y here if you want to enable support for Raydium RM69220-based
|
||||
display panels, such as the BOE BF068MWM-TD0 which can be found in
|
||||
the Nothing Phone (3a).
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called panel-raydium-rm69220.
|
||||
|
||||
config DRM_PANEL_RAYDIUM_RM69380
|
||||
tristate "Raydium RM69380-based DSI panel"
|
||||
depends on GPIOLIB
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672E) += panel-novatek-nt36672e.o
|
|||
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT37700F) += panel-novatek-nt37700f.o
|
||||
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT37801) += panel-novatek-nt37801.o
|
||||
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT39016) += panel-novatek-nt39016.o
|
||||
obj-$(CONFIG_DRM_PANEL_NOVATEK_NT51021) += panel-novatek-nt51021.o
|
||||
obj-$(CONFIG_DRM_PANEL_MANTIX_MLAF057WE51) += panel-mantix-mlaf057we51.o
|
||||
obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) += panel-olimex-lcd-olinuxino.o
|
||||
obj-$(CONFIG_DRM_PANEL_ORISETECH_OTA5601A) += panel-orisetech-ota5601a.o
|
||||
|
|
@ -83,6 +84,7 @@ obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM67191) += panel-raydium-rm67191.o
|
|||
obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM67200) += panel-raydium-rm67200.o
|
||||
obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o
|
||||
obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM692E5) += panel-raydium-rm692e5.o
|
||||
obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM69220) += panel-raydium-rm69220.o
|
||||
obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM69380) += panel-raydium-rm69380.o
|
||||
obj-$(CONFIG_DRM_PANEL_RENESAS_R61307) += panel-renesas-r61307.o
|
||||
obj-$(CONFIG_DRM_PANEL_RENESAS_R63419) += panel-renesas-r63419.o
|
||||
|
|
|
|||
|
|
@ -1958,6 +1958,7 @@ static const struct edp_panel_entry edp_panels[] = {
|
|||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x0290, &delay_200_500_e50, "B140XTN07.5"),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x04a4, &delay_200_500_e50, "B122UAN01.0"),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x0ba4, &delay_200_500_e50, "B140QAX01.H"),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x0db3, &delay_200_500_e50, "Unknown"),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x105c, &delay_200_500_e50, "B116XTN01.0"),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, "B120XAN01.0"),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x125c, &delay_200_500_e50, "Unknown"),
|
||||
|
|
@ -1986,6 +1987,7 @@ static const struct edp_panel_entry edp_panels[] = {
|
|||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, &delay_200_500_e50, "B116XAN06.3"),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, &delay_200_500_e50, "B140HAK02.7"),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x643d, &delay_200_500_e50, "B140HAN06.4"),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x65a9, &delay_200_500_e50, "B140HAN04.0"),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x67a8, &delay_200_500_e200, "B140XTK02.4"),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x723c, &delay_200_500_e50, "B140XTN07.2"),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0x73aa, &delay_200_500_e50, "B116XTN02.3"),
|
||||
|
|
@ -2003,6 +2005,7 @@ static const struct edp_panel_entry edp_panels[] = {
|
|||
EDP_PANEL_ENTRY('A', 'U', 'O', 0xd497, &delay_200_500_e50, "B120XAN01.0"),
|
||||
EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, &delay_200_500_e50, "B140XTN07.7"),
|
||||
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x03f4, &delay_200_500_e50, "NV140FHD-N43"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0607, &delay_200_500_e200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0608, &delay_200_500_e50, "NT116WHM-N11"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0609, &delay_200_500_e50_po2e200, "NT116WHM-N21 V4.1"),
|
||||
|
|
@ -2198,6 +2201,7 @@ static const struct edp_panel_entry edp_panels[] = {
|
|||
EDP_PANEL_ENTRY('S', 'H', 'P', 0x1523, &delay_80_500_e50, "LQ140M1JW46"),
|
||||
EDP_PANEL_ENTRY('S', 'H', 'P', 0x153a, &delay_200_500_e50, "LQ140T1JH01"),
|
||||
EDP_PANEL_ENTRY('S', 'H', 'P', 0x154c, &delay_200_500_p2e100, "LQ116M1JW10"),
|
||||
EDP_PANEL_ENTRY('S', 'H', 'P', 0x1572, &delay_200_500_e200, "LQ138P1JX61"),
|
||||
EDP_PANEL_ENTRY('S', 'H', 'P', 0x158f, &delay_200_500_p2e100, "LQ134Z1"),
|
||||
EDP_PANEL_ENTRY('S', 'H', 'P', 0x1593, &delay_200_500_p2e100, "LQ134N1"),
|
||||
EDP_PANEL_ENTRY('S', 'H', 'P', 0x15a7, &delay_200_500_e200, "LQ120P1JX51"),
|
||||
|
|
|
|||
875
drivers/gpu/drm/panel/panel-novatek-nt51021.c
Normal file
875
drivers/gpu/drm/panel/panel-novatek-nt51021.c
Normal file
|
|
@ -0,0 +1,875 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright (c) 2026, Ryan Brue <ryanbrue.dev@gmail.com>
|
||||
// Copyright (c) 2025, Nickolay Goppen <setotau@mainlining.org>
|
||||
// Copyright (c) 2024, Alexey Minnekhanov <alexeymin@minlexx.ru>
|
||||
|
||||
/*
|
||||
* This panel IC doesn't use the set_display_on command although
|
||||
* it uses set_display_off command. This is not an error.
|
||||
*/
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
#include <drm/drm_modes.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
||||
struct novatek_nt51021_desc;
|
||||
|
||||
struct novatek_nt51021_variant {
|
||||
int (*init)(struct novatek_nt51021_desc *ctx);
|
||||
int (*off)(struct novatek_nt51021_desc *ctx);
|
||||
|
||||
const struct drm_display_mode *display_mode;
|
||||
unsigned long mode_flags;
|
||||
};
|
||||
|
||||
struct novatek_nt51021_desc {
|
||||
struct drm_panel panel;
|
||||
struct mipi_dsi_device *dsi;
|
||||
struct regulator_bulk_data *supplies;
|
||||
struct gpio_desc *reset_gpio;
|
||||
|
||||
const struct novatek_nt51021_variant *variant;
|
||||
};
|
||||
|
||||
static const struct regulator_bulk_data nt51021_novatek_supplies[] = {
|
||||
{ .supply = "vdd" },
|
||||
{ .supply = "avdd" },
|
||||
{ .supply = "havdd" },
|
||||
};
|
||||
|
||||
static inline struct novatek_nt51021_desc *to_novatek_panel(struct drm_panel *panel)
|
||||
{
|
||||
return container_of_const(panel, struct novatek_nt51021_desc, panel);
|
||||
}
|
||||
|
||||
static void nt51021_novatek_reset(struct novatek_nt51021_desc *ctx)
|
||||
{
|
||||
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
||||
msleep(20);
|
||||
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
|
||||
usleep_range(10000, 11000);
|
||||
}
|
||||
|
||||
static void nt51021_cabc_on(struct mipi_dsi_multi_context *dsi_ctx)
|
||||
{
|
||||
if (dsi_ctx->accum_err)
|
||||
return;
|
||||
|
||||
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x8f, 0x00);
|
||||
mipi_dsi_usleep_range(dsi_ctx, 1000, 2000);
|
||||
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x8f, 0xa5);
|
||||
mipi_dsi_usleep_range(dsi_ctx, 1000, 2000);
|
||||
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x83, 0xbb);
|
||||
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x84, 0x22);
|
||||
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x90, 0x40);
|
||||
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x8f, 0x00);
|
||||
mipi_dsi_usleep_range(dsi_ctx, 1000, 2000);
|
||||
}
|
||||
|
||||
static void nt51021_cabc_off(struct mipi_dsi_multi_context *dsi_ctx)
|
||||
{
|
||||
if (dsi_ctx->accum_err)
|
||||
return;
|
||||
|
||||
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x8f, 0xa5);
|
||||
mipi_dsi_usleep_range(dsi_ctx, 1000, 2000);
|
||||
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x83, 0xbb);
|
||||
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x84, 0x22);
|
||||
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x90, 0xc0);
|
||||
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x8f, 0x00);
|
||||
mipi_dsi_usleep_range(dsi_ctx, 1000, 2000);
|
||||
}
|
||||
|
||||
static int boe_tv080wum_nx2_init(struct novatek_nt51021_desc *ctx)
|
||||
{
|
||||
struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
|
||||
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0xa5);
|
||||
mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x01, 0x00);
|
||||
mipi_dsi_msleep(&dsi_ctx, 20);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0xa5);
|
||||
mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0x00);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x00);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8c, 0x8e);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x6c);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0x8b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0xf0);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8b, 0x10);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0x20);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x97, 0x00);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfa, 0x15);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfd, 0x1b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0xaa);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x11);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0x4b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x85, 0x04);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x86, 0x08);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x98, 0xc1);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0xaa);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x11);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0x05);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc1, 0x0c);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc2, 0x22);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc3, 0x34);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc4, 0x44);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc5, 0x52);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc6, 0x5d);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc7, 0x66);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0x70);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc9, 0x00);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xca, 0x11);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcb, 0x3b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcc, 0x53);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x69);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xce, 0x6a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcf, 0x6c);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd0, 0x6b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd1, 0x75);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd2, 0x83);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd3, 0x99);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd4, 0x9a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd5, 0xd0);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6, 0xd6);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd7, 0xdb);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd8, 0xe1);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd9, 0xe7);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xda, 0xed);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdb, 0xf4);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdc, 0xfb);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdd, 0xff);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xde, 0xff);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdf, 0x0f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe0, 0x15);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe1, 0x1c);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe2, 0x32);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe3, 0x44);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe4, 0x52);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe5, 0x60);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe6, 0x6b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe7, 0x74);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe8, 0x7e);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe9, 0x14);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xea, 0x25);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xeb, 0x4d);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xec, 0x63);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xed, 0x71);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xee, 0x6a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xef, 0x6c);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x6b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf1, 0x75);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf2, 0x83);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf3, 0x99);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf4, 0x9a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf5, 0xd0);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf6, 0xd6);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf7, 0xdb);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf8, 0xe1);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf9, 0xe7);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfa, 0xed);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0xf4);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfc, 0xfb);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfd, 0xff);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfe, 0xff);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x0f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0xbb);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x22);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa1, 0xff);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa2, 0xfe);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa3, 0xfa);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa4, 0xf7);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa5, 0xf3);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa6, 0xf1);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa7, 0xed);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa8, 0xeb);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0xe9);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xaa, 0xe6);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xaf, 0x00);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb0, 0x35);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb1, 0x89);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb2, 0x99);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb3, 0x99);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb4, 0x0d);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb5, 0x1a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb6, 0x16);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9a, 0x10);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9b, 0x00);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x96, 0xe6);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x99, 0x06);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0x05);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc1, 0x0c);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc2, 0x22);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc3, 0x34);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc4, 0x44);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc5, 0x52);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc6, 0x5d);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc7, 0x66);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0x70);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc9, 0x00);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xca, 0x11);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcb, 0x3b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcc, 0x53);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x69);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xce, 0x6a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcf, 0x6c);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd0, 0x6b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd1, 0x75);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd2, 0x83);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd3, 0x99);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd4, 0x9a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd5, 0xd0);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6, 0xd6);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd7, 0xdb);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd8, 0xe1);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd9, 0xe7);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xda, 0xed);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdb, 0xf4);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdc, 0xfb);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdd, 0xff);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xde, 0xff);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdf, 0x0f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe0, 0x15);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe1, 0x1c);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe2, 0x32);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe3, 0x44);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe4, 0x52);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe5, 0x60);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe6, 0x6b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe7, 0x74);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe8, 0x7e);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe9, 0x14);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xea, 0x25);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xeb, 0x4d);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xec, 0x63);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xed, 0x71);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xee, 0x6a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xef, 0x6c);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x6b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf1, 0x75);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf2, 0x83);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf3, 0x99);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf4, 0x9a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf5, 0xd0);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf6, 0xd6);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf7, 0xdb);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf8, 0xe1);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf9, 0xe7);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfa, 0xed);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0xf4);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfc, 0xfb);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfd, 0xff);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfe, 0xff);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x0f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0xcc);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x33);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0x05);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc1, 0x0c);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc2, 0x22);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc3, 0x34);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc4, 0x44);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc5, 0x52);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc6, 0x5d);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc7, 0x66);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0x70);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc9, 0x00);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xca, 0x11);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcb, 0x3b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcc, 0x53);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x69);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xce, 0x6a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcf, 0x6c);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd0, 0x6b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd1, 0x75);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd2, 0x83);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd3, 0x99);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd4, 0x9a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd5, 0xd0);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6, 0xd6);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd7, 0xdb);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd8, 0xe1);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd9, 0xe7);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xda, 0xed);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdb, 0xf4);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdc, 0xfb);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdd, 0xff);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xde, 0xff);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdf, 0x0f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe0, 0x15);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe1, 0x1c);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe2, 0x32);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe3, 0x44);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe4, 0x52);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe5, 0x60);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe6, 0x6b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe7, 0x74);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe8, 0x7e);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe9, 0x14);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xea, 0x25);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xeb, 0x4d);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xec, 0x63);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xed, 0x71);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xee, 0x6a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xef, 0x6c);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x6b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf1, 0x75);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf2, 0x83);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf3, 0x99);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf4, 0x9a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf5, 0xd0);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf6, 0xd6);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf7, 0xdb);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf8, 0xe1);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf9, 0xe7);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfa, 0xed);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0xf4);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfc, 0xfb);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfd, 0xff);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfe, 0xff);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x0f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0x00);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x00);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9f, 0xff);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0xbb);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x22);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x94, 0xba);
|
||||
mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
|
||||
mipi_dsi_usleep_range(&dsi_ctx, 5000, 6000);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0x00);
|
||||
mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000);
|
||||
|
||||
nt51021_cabc_on(&dsi_ctx);
|
||||
|
||||
return dsi_ctx.accum_err;
|
||||
}
|
||||
|
||||
static int boe_tv101wum_nx0_init(struct novatek_nt51021_desc *ctx)
|
||||
{
|
||||
struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
|
||||
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0xa5);
|
||||
mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x01, 0x00);
|
||||
mipi_dsi_msleep(&dsi_ctx, 20);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0xa5);
|
||||
mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0x00);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x00);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8c, 0x8e);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfa, 0x12);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfd, 0x1b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x6c);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0xfc);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x97, 0x00);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8b, 0x10);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0x20);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0xaa);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x11);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0x4b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x85, 0x04);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x86, 0x08);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x98, 0xc1);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9c, 0x10);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0xaa);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x11);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0x0e);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc1, 0x11);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc2, 0x1f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc3, 0x30);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc4, 0x3f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc5, 0x4b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc6, 0x55);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc7, 0x5d);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0x68);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc9, 0xe3);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xca, 0xea);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcb, 0x01);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcc, 0x0a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x0a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xce, 0x07);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcf, 0x08);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd0, 0x09);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd1, 0x1d);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd2, 0x31);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd3, 0x52);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd4, 0x5b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd5, 0xb6);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6, 0xbd);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd7, 0xc5);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd8, 0xcd);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd9, 0xd6);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xda, 0xe0);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdb, 0xeb);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdc, 0xf8);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdd, 0xff);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xde, 0xfc);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdf, 0x0f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe0, 0x0e);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe1, 0x11);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe2, 0x1f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe3, 0x30);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe4, 0x3f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe5, 0x4b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe6, 0x55);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe7, 0x5d);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe8, 0x68);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe9, 0xe3);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xea, 0xea);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xeb, 0x01);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xec, 0x0a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xed, 0x0a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xee, 0x07);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xef, 0x08);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x09);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf1, 0x1d);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf2, 0x31);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf3, 0x52);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf4, 0x5b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf5, 0xb6);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf6, 0xbd);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf7, 0xc5);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf8, 0xcd);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf9, 0xd6);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfa, 0xe0);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0xeb);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfc, 0xf8);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfd, 0xff);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfe, 0xfc);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x0f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0xbb);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x22);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa1, 0xff);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa2, 0xfe);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa3, 0xfa);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa4, 0xf7);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa5, 0xf3);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa6, 0xf1);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa7, 0xed);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa8, 0xeb);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0xe9);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xaa, 0xe6);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xaf, 0x00);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb0, 0x12);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb1, 0x23);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb2, 0x34);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb3, 0x77);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb4, 0x0d);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb5, 0x1a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb6, 0x16);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9a, 0x10);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9b, 0x00);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x96, 0xe6);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x99, 0x06);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0x0e);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc1, 0x11);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc2, 0x1f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc3, 0x30);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc4, 0x3f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc5, 0x4b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc6, 0x55);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc7, 0x5d);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0x68);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc9, 0xe3);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xca, 0xea);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcb, 0x01);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcc, 0x0a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x0a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xce, 0x07);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcf, 0x08);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd0, 0x09);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd1, 0x1d);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd2, 0x31);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd3, 0x52);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd4, 0x5b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd5, 0xb6);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6, 0xbd);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd7, 0xc5);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd8, 0xcd);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd9, 0xd6);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xda, 0xe0);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdb, 0xeb);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdc, 0xf8);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdd, 0xff);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xde, 0xfc);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdf, 0x0f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe0, 0x0e);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe1, 0x11);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe2, 0x1f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe3, 0x30);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe4, 0x3f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe5, 0x4b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe6, 0x55);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe7, 0x5d);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe8, 0x68);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe9, 0xe3);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xea, 0xea);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xeb, 0x01);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xec, 0x0a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xed, 0x0a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xee, 0x07);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xef, 0x08);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x09);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf1, 0x1d);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf2, 0x31);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf3, 0x52);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf4, 0x5b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf5, 0xb6);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf6, 0xbd);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf7, 0xc5);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf8, 0xcd);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf9, 0xd6);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfa, 0xe0);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0xeb);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfc, 0xf8);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfd, 0xff);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfe, 0xfc);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x0f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0xcc);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x33);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0x0e);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc1, 0x11);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc2, 0x1f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc3, 0x30);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc4, 0x3f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc5, 0x4b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc6, 0x55);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc7, 0x5d);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0x68);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc9, 0xe3);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xca, 0xea);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcb, 0x01);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcc, 0x0a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x0a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xce, 0x07);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcf, 0x08);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd0, 0x09);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd1, 0x1d);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd2, 0x31);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd3, 0x52);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd4, 0x5b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd5, 0xb6);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6, 0xbd);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd7, 0xc5);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd8, 0xcd);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd9, 0xd6);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xda, 0xe0);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdb, 0xeb);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdc, 0xf8);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdd, 0xff);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xde, 0xfc);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xdf, 0x0f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe0, 0x0e);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe1, 0x11);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe2, 0x1f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe3, 0x30);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe4, 0x3f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe5, 0x4b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe6, 0x55);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe7, 0x5d);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe8, 0x68);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe9, 0xe3);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xea, 0xea);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xeb, 0x01);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xec, 0x0a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xed, 0x0a);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xee, 0x07);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xef, 0x08);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x09);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf1, 0x1d);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf2, 0x31);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf3, 0x52);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf4, 0x5b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf5, 0xb6);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf6, 0xbd);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf7, 0xc5);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf8, 0xcd);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf9, 0xd6);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfa, 0xe0);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfb, 0xeb);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfc, 0xf8);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfd, 0xff);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfe, 0xfc);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0x0f);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0x00);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x00);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9f, 0xff);
|
||||
mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
|
||||
mipi_dsi_usleep_range(&dsi_ctx, 5000, 6000);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0x00);
|
||||
mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000);
|
||||
|
||||
nt51021_cabc_on(&dsi_ctx);
|
||||
mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000);
|
||||
|
||||
return dsi_ctx.accum_err;
|
||||
}
|
||||
|
||||
static int boe_tv101wum_nm0_init(struct novatek_nt51021_desc *ctx)
|
||||
{
|
||||
struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
|
||||
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0xa5);
|
||||
mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x01, 0x00);
|
||||
mipi_dsi_msleep(&dsi_ctx, 20);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0xa5);
|
||||
mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0x00);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x00);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8c, 0x80);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x6c);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0x8b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0xf0);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x97, 0x00);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8b, 0x10);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0x20);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0xaa);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x11);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0x4b);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x85, 0x04);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x86, 0x08);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9c, 0x10);
|
||||
mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
|
||||
mipi_dsi_msleep(&dsi_ctx, 120);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0x00);
|
||||
mipi_dsi_msleep(&dsi_ctx, 5);
|
||||
|
||||
return dsi_ctx.accum_err;
|
||||
}
|
||||
|
||||
static int nt51021_novatek_with_cabc_off(struct novatek_nt51021_desc *ctx)
|
||||
{
|
||||
struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
|
||||
|
||||
nt51021_cabc_off(&dsi_ctx);
|
||||
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0xa5);
|
||||
mipi_dsi_msleep(&dsi_ctx, 20);
|
||||
mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
|
||||
mipi_dsi_msleep(&dsi_ctx, 130);
|
||||
mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
|
||||
mipi_dsi_msleep(&dsi_ctx, 70);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0x00);
|
||||
mipi_dsi_usleep_range(&dsi_ctx, 4000, 5000);
|
||||
|
||||
return dsi_ctx.accum_err;
|
||||
}
|
||||
|
||||
static int nt51021_novatek_off(struct novatek_nt51021_desc *ctx)
|
||||
{
|
||||
struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
|
||||
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0xa5);
|
||||
mipi_dsi_msleep(&dsi_ctx, 20);
|
||||
mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
|
||||
mipi_dsi_msleep(&dsi_ctx, 130);
|
||||
mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
|
||||
mipi_dsi_msleep(&dsi_ctx, 70);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0x00);
|
||||
mipi_dsi_usleep_range(&dsi_ctx, 4000, 5000);
|
||||
|
||||
return dsi_ctx.accum_err;
|
||||
}
|
||||
|
||||
static int nt51021_novatek_prepare(struct drm_panel *panel)
|
||||
{
|
||||
struct novatek_nt51021_desc *ctx = to_novatek_panel(panel);
|
||||
struct device *dev = &ctx->dsi->dev;
|
||||
int ret;
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(nt51021_novatek_supplies), ctx->supplies);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to enable regulators: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
nt51021_novatek_reset(ctx);
|
||||
|
||||
ret = ctx->variant->init(ctx);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to initialize panel: %d\n", ret);
|
||||
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
||||
regulator_bulk_disable(ARRAY_SIZE(nt51021_novatek_supplies), ctx->supplies);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nt51021_novatek_unprepare(struct drm_panel *panel)
|
||||
{
|
||||
struct novatek_nt51021_desc *ctx = to_novatek_panel(panel);
|
||||
struct device *dev = &ctx->dsi->dev;
|
||||
int ret;
|
||||
|
||||
ret = ctx->variant->off(ctx);
|
||||
if (ret < 0)
|
||||
dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
|
||||
|
||||
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
||||
regulator_bulk_disable(ARRAY_SIZE(nt51021_novatek_supplies), ctx->supplies);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nt51021_novatek_get_modes(struct drm_panel *panel,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct novatek_nt51021_desc *ctx = to_novatek_panel(panel);
|
||||
|
||||
return drm_connector_helper_get_modes_fixed(connector,
|
||||
ctx->variant->display_mode);
|
||||
}
|
||||
|
||||
static const struct drm_panel_funcs nt51021_novatek_panel_funcs = {
|
||||
.prepare = nt51021_novatek_prepare,
|
||||
.unprepare = nt51021_novatek_unprepare,
|
||||
.get_modes = nt51021_novatek_get_modes,
|
||||
};
|
||||
|
||||
static int nt51021_novatek_probe(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
struct device *dev = &dsi->dev;
|
||||
struct novatek_nt51021_desc *ctx;
|
||||
int ret;
|
||||
|
||||
ctx = devm_drm_panel_alloc(dev, struct novatek_nt51021_desc, panel,
|
||||
&nt51021_novatek_panel_funcs,
|
||||
DRM_MODE_CONNECTOR_DSI);
|
||||
if (IS_ERR(ctx))
|
||||
return PTR_ERR(ctx);
|
||||
|
||||
ctx->variant = of_device_get_match_data(dev);
|
||||
if (!ctx->variant)
|
||||
return dev_err_probe(dev, -ENODEV, "No match data\n");
|
||||
|
||||
ret = devm_regulator_bulk_get_const(dev,
|
||||
ARRAY_SIZE(nt51021_novatek_supplies),
|
||||
nt51021_novatek_supplies,
|
||||
&ctx->supplies);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(ctx->reset_gpio))
|
||||
return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
|
||||
"Failed to get reset-gpios\n");
|
||||
|
||||
ctx->dsi = dsi;
|
||||
mipi_dsi_set_drvdata(dsi, ctx);
|
||||
|
||||
dsi->lanes = 4;
|
||||
dsi->format = MIPI_DSI_FMT_RGB888;
|
||||
dsi->mode_flags = ctx->variant->mode_flags;
|
||||
|
||||
ctx->panel.prepare_prev_first = true;
|
||||
|
||||
ret = drm_panel_of_backlight(&ctx->panel);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to get backlight\n");
|
||||
|
||||
ret = devm_drm_panel_add(dev, &ctx->panel);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_mipi_dsi_attach(dev, dsi);
|
||||
}
|
||||
|
||||
static const struct drm_display_mode boe_tv080wum_nx2_mode = {
|
||||
.clock = (1200 + 84 + 4 + 60) * (1920 + 36 + 1 + 25) * 60 / 1000,
|
||||
.hdisplay = 1200,
|
||||
.hsync_start = 1200 + 84,
|
||||
.hsync_end = 1200 + 84 + 4,
|
||||
.htotal = 1200 + 84 + 4 + 60,
|
||||
.vdisplay = 1920,
|
||||
.vsync_start = 1920 + 36,
|
||||
.vsync_end = 1920 + 36 + 1,
|
||||
.vtotal = 1920 + 36 + 1 + 25,
|
||||
.width_mm = 107,
|
||||
.height_mm = 172,
|
||||
.type = DRM_MODE_TYPE_DRIVER,
|
||||
};
|
||||
|
||||
static const struct drm_display_mode boe_tv101wum_nm0_mode = {
|
||||
.clock = 163333,
|
||||
.hdisplay = 1200,
|
||||
.hsync_start = 1200 + 110,
|
||||
.hsync_end = 1200 + 110 + 1,
|
||||
.htotal = 1200 + 110 + 1 + 32,
|
||||
.vdisplay = 1920,
|
||||
.vsync_start = 1920 + 11,
|
||||
.vsync_end = 1920 + 11 + 1,
|
||||
.vtotal = 1920 + 11 + 1 + 14,
|
||||
.width_mm = 135,
|
||||
.height_mm = 216,
|
||||
.type = DRM_MODE_TYPE_DRIVER,
|
||||
};
|
||||
|
||||
static const struct drm_display_mode boe_tv101wum_nx0_mode = {
|
||||
.clock = (1200 + 172 + 4 + 32) * (1920 + 25 + 1 + 14) * 60 / 1000,
|
||||
.hdisplay = 1200,
|
||||
.hsync_start = 1200 + 172,
|
||||
.hsync_end = 1200 + 172 + 4,
|
||||
.htotal = 1200 + 172 + 4 + 32,
|
||||
.vdisplay = 1920,
|
||||
.vsync_start = 1920 + 25,
|
||||
.vsync_end = 1920 + 25 + 1,
|
||||
.vtotal = 1920 + 25 + 1 + 14,
|
||||
.width_mm = 135,
|
||||
.height_mm = 216,
|
||||
.type = DRM_MODE_TYPE_DRIVER,
|
||||
};
|
||||
|
||||
#define NT51021_BURST_MODE_FLAGS (MIPI_DSI_MODE_VIDEO | \
|
||||
MIPI_DSI_MODE_VIDEO_BURST | \
|
||||
MIPI_DSI_MODE_NO_EOT_PACKET | \
|
||||
MIPI_DSI_MODE_LPM)
|
||||
|
||||
static const struct novatek_nt51021_variant boe_tv080wum_nx2_data = {
|
||||
.init = boe_tv080wum_nx2_init,
|
||||
.off = nt51021_novatek_with_cabc_off,
|
||||
.display_mode = &boe_tv080wum_nx2_mode,
|
||||
.mode_flags = NT51021_BURST_MODE_FLAGS,
|
||||
};
|
||||
|
||||
static const struct novatek_nt51021_variant boe_tv101wum_nm0_data = {
|
||||
.init = boe_tv101wum_nm0_init,
|
||||
.off = nt51021_novatek_off,
|
||||
.display_mode = &boe_tv101wum_nm0_mode,
|
||||
.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM,
|
||||
};
|
||||
|
||||
static const struct novatek_nt51021_variant boe_tv101wum_nx0_data = {
|
||||
.init = boe_tv101wum_nx0_init,
|
||||
.off = nt51021_novatek_with_cabc_off,
|
||||
.display_mode = &boe_tv101wum_nx0_mode,
|
||||
.mode_flags = NT51021_BURST_MODE_FLAGS,
|
||||
};
|
||||
|
||||
static const struct of_device_id nt51021_novatek_of_match[] = {
|
||||
{ .compatible = "boe,tv080wum-nx2", .data = &boe_tv080wum_nx2_data },
|
||||
{ .compatible = "boe,tv101wum-nm0", .data = &boe_tv101wum_nm0_data },
|
||||
{ .compatible = "boe,tv101wum-nx0", .data = &boe_tv101wum_nx0_data },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, nt51021_novatek_of_match);
|
||||
|
||||
static struct mipi_dsi_driver nt51021_boe_driver = {
|
||||
.probe = nt51021_novatek_probe,
|
||||
.driver = {
|
||||
.name = "panel-novatek-nt51021",
|
||||
.of_match_table = nt51021_novatek_of_match,
|
||||
},
|
||||
};
|
||||
module_mipi_dsi_driver(nt51021_boe_driver);
|
||||
|
||||
MODULE_AUTHOR("Nickolay Goppen <setotau@mainlining.org>");
|
||||
MODULE_AUTHOR("Alexey Minnekhanov <alexeymin@minlexx.ru>");
|
||||
MODULE_AUTHOR("Ryan Brue <ryanbrue.dev@gmail.com>");
|
||||
MODULE_DESCRIPTION("DRM driver for Novatek NT51021-based DSI panels");
|
||||
MODULE_LICENSE("GPL");
|
||||
417
drivers/gpu/drm/panel/panel-raydium-rm69220.c
Normal file
417
drivers/gpu/drm/panel/panel-raydium-rm69220.c
Normal file
|
|
@ -0,0 +1,417 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree.
|
||||
* Copyright (c) 2026 Alexander Koskovich <akoskovich@pm.me>
|
||||
*/
|
||||
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device-id/of.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <video/mipi_display.h>
|
||||
|
||||
#include <drm/display/drm_dsc.h>
|
||||
#include <drm/display/drm_dsc_helper.h>
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
#include <drm/drm_modes.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
||||
struct raydium_rm69220 {
|
||||
struct drm_panel panel;
|
||||
struct mipi_dsi_device *dsi;
|
||||
struct drm_dsc_config dsc;
|
||||
struct regulator_bulk_data *supplies;
|
||||
struct gpio_desc *reset_gpio;
|
||||
};
|
||||
|
||||
static const struct regulator_bulk_data raydium_rm69220_supplies[] = {
|
||||
{ .supply = "vddio" },
|
||||
{ .supply = "dvdd" },
|
||||
{ .supply = "vci" },
|
||||
};
|
||||
|
||||
static inline
|
||||
struct raydium_rm69220 *to_raydium_rm69220(struct drm_panel *panel)
|
||||
{
|
||||
return container_of(panel, struct raydium_rm69220, panel);
|
||||
}
|
||||
|
||||
static void raydium_rm69220_reset(struct raydium_rm69220 *ctx)
|
||||
{
|
||||
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
|
||||
usleep_range(1000, 2000);
|
||||
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
||||
usleep_range(1000, 2000);
|
||||
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
|
||||
msleep(32);
|
||||
}
|
||||
|
||||
static int raydium_rm69220_on(struct raydium_rm69220 *ctx)
|
||||
{
|
||||
struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
|
||||
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x76);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9a, 0x10);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9b, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x77);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9a, 0x10);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9b, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x78);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9a, 0x10);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9b, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x79);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9a, 0xf0);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9b, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x74);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1a, 0xe0);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x1b, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x40);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xa9, 0x68);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xab, 0x22);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x40);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, 0xa6);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbf, 0x87);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x82);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x90);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0xd4);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x08);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xa2, 0x04);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfa, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0xd2);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x97, 0x08);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x36, 0x11);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0xab);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3a, 0x30);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3b, 0x80);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3d, 0x09);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x58);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x04);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0x38);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x42, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x0d);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x02);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x45, 0x1c);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x46, 0x02);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x47, 0x1c);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x48, 0x02);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x49, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4a, 0x02);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4b, 0x0e);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4d, 0x20);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4e, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4f, 0x39);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x51, 0x07);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x53, 0x0c);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x54, 0x08);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x56, 0x07);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x58, 0xd3);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0x18);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5a, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5b, 0x10);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5c, 0xf0);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5d, 0x07);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5e, 0x10);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x20);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x60, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x61, 0x06);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x62, 0x0f);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x63, 0x0f);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x64, 0x33);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x0e);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x1c);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x67, 0x2a);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x68, 0x38);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x69, 0x46);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6a, 0x54);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6b, 0x62);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6c, 0x69);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x70);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6e, 0x77);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x79);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x70, 0x7b);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x71, 0x7d);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x72, 0x7e);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x73, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x74, 0x02);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0x22);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x76, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x77, 0x2a);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x78, 0x40);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x79, 0x2a);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7a, 0xbe);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7b, 0x3a);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7c, 0xfc);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7d, 0x3a);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7e, 0xfa);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7f, 0x3a);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0xf8);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x81, 0x3b);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x82, 0x38);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x83, 0x3b);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x84, 0x78);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x85, 0x3b);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x86, 0xb6);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x87, 0x4b);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x88, 0xf6);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x89, 0x4c);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x8a, 0x34);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x8b, 0x4c);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x8c, 0x74);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x8d, 0x5c);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x8e, 0x74);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x8f, 0x8c);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x90, 0xf4);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x91, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x92, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x93, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x94, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x95, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x96, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0xa0);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x66, 0x06);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x49);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x87, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3f, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0xa0);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x07);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4b, 0x40);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4d, 0x40);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0xa1);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x58, 0x67);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x75, 0xa7);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2f, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfa, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, 0x03);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2, 0x03);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x51, 0x0d, 0xbb);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x00);
|
||||
mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
|
||||
mipi_dsi_msleep(&dsi_ctx, 80);
|
||||
mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
|
||||
mipi_dsi_usleep_range(&dsi_ctx, 10000, 11000);
|
||||
|
||||
return dsi_ctx.accum_err;
|
||||
}
|
||||
|
||||
static int raydium_rm69220_off(struct raydium_rm69220 *ctx)
|
||||
{
|
||||
struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
|
||||
|
||||
mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
|
||||
mipi_dsi_msleep(&dsi_ctx, 100);
|
||||
mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
|
||||
mipi_dsi_msleep(&dsi_ctx, 100);
|
||||
|
||||
return dsi_ctx.accum_err;
|
||||
}
|
||||
|
||||
static int raydium_rm69220_prepare(struct drm_panel *panel)
|
||||
{
|
||||
struct raydium_rm69220 *ctx = to_raydium_rm69220(panel);
|
||||
struct device *dev = &ctx->dsi->dev;
|
||||
struct drm_dsc_picture_parameter_set pps;
|
||||
int ret;
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(raydium_rm69220_supplies), ctx->supplies);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to enable regulators: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
raydium_rm69220_reset(ctx);
|
||||
|
||||
ret = raydium_rm69220_on(ctx);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to initialize panel: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
drm_dsc_pps_payload_pack(&pps, &ctx->dsc);
|
||||
|
||||
ret = mipi_dsi_picture_parameter_set(ctx->dsi, &pps);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to transmit PPS: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = mipi_dsi_compression_mode(ctx->dsi, true);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to enable compression mode: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
msleep(28);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
||||
regulator_bulk_disable(ARRAY_SIZE(raydium_rm69220_supplies), ctx->supplies);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int raydium_rm69220_unprepare(struct drm_panel *panel)
|
||||
{
|
||||
struct raydium_rm69220 *ctx = to_raydium_rm69220(panel);
|
||||
struct device *dev = &ctx->dsi->dev;
|
||||
int ret;
|
||||
|
||||
ret = raydium_rm69220_off(ctx);
|
||||
if (ret < 0)
|
||||
dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
|
||||
|
||||
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
||||
regulator_bulk_disable(ARRAY_SIZE(raydium_rm69220_supplies), ctx->supplies);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_display_mode raydium_rm69220_mode = {
|
||||
.clock = (1080 + 36 + 4 + 36) * (2392 + 72 + 4 + 52) * 120 / 1000,
|
||||
.hdisplay = 1080,
|
||||
.hsync_start = 1080 + 36,
|
||||
.hsync_end = 1080 + 36 + 4,
|
||||
.htotal = 1080 + 36 + 4 + 36,
|
||||
.vdisplay = 2392,
|
||||
.vsync_start = 2392 + 72,
|
||||
.vsync_end = 2392 + 72 + 4,
|
||||
.vtotal = 2392 + 72 + 4 + 52,
|
||||
.width_mm = 71,
|
||||
.height_mm = 157,
|
||||
.type = DRM_MODE_TYPE_DRIVER,
|
||||
};
|
||||
|
||||
static int raydium_rm69220_get_modes(struct drm_panel *panel,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
return drm_connector_helper_get_modes_fixed(connector, &raydium_rm69220_mode);
|
||||
}
|
||||
|
||||
static const struct drm_panel_funcs raydium_rm69220_panel_funcs = {
|
||||
.prepare = raydium_rm69220_prepare,
|
||||
.unprepare = raydium_rm69220_unprepare,
|
||||
.get_modes = raydium_rm69220_get_modes,
|
||||
};
|
||||
|
||||
static int raydium_rm69220_bl_update_status(struct backlight_device *bl)
|
||||
{
|
||||
struct mipi_dsi_device *dsi = bl_get_data(bl);
|
||||
u16 brightness = backlight_get_brightness(bl);
|
||||
int ret;
|
||||
|
||||
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
|
||||
|
||||
ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct backlight_ops raydium_rm69220_bl_ops = {
|
||||
.update_status = raydium_rm69220_bl_update_status,
|
||||
};
|
||||
|
||||
static struct backlight_device *
|
||||
raydium_rm69220_create_backlight(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
struct device *dev = &dsi->dev;
|
||||
const struct backlight_properties props = {
|
||||
.type = BACKLIGHT_RAW,
|
||||
.brightness = 2946,
|
||||
.max_brightness = 3442, /* 4095 is HBM max */
|
||||
};
|
||||
|
||||
return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
|
||||
&raydium_rm69220_bl_ops, &props);
|
||||
}
|
||||
|
||||
static int raydium_rm69220_probe(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
struct device *dev = &dsi->dev;
|
||||
struct raydium_rm69220 *ctx;
|
||||
int ret;
|
||||
|
||||
ctx = devm_drm_panel_alloc(dev, struct raydium_rm69220, panel,
|
||||
&raydium_rm69220_panel_funcs,
|
||||
DRM_MODE_CONNECTOR_DSI);
|
||||
if (IS_ERR(ctx))
|
||||
return PTR_ERR(ctx);
|
||||
|
||||
ret = devm_regulator_bulk_get_const(dev,
|
||||
ARRAY_SIZE(raydium_rm69220_supplies),
|
||||
raydium_rm69220_supplies,
|
||||
&ctx->supplies);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(ctx->reset_gpio))
|
||||
return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
|
||||
"Failed to get reset-gpios\n");
|
||||
|
||||
ctx->dsi = dsi;
|
||||
|
||||
dsi->lanes = 4;
|
||||
dsi->format = MIPI_DSI_FMT_RGB101010;
|
||||
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_NO_EOT_PACKET |
|
||||
MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM |
|
||||
MIPI_DSI_MODE_DSC_ALL_SLICES_IN_PKT;
|
||||
|
||||
ctx->panel.prepare_prev_first = true;
|
||||
|
||||
ctx->panel.backlight = raydium_rm69220_create_backlight(dsi);
|
||||
if (IS_ERR(ctx->panel.backlight))
|
||||
return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
|
||||
"Failed to create backlight\n");
|
||||
|
||||
ret = devm_drm_panel_add(dev, &ctx->panel);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* This panel only supports DSC; unconditionally enable it */
|
||||
dsi->dsc = &ctx->dsc;
|
||||
|
||||
ctx->dsc.dsc_version_major = 1;
|
||||
ctx->dsc.dsc_version_minor = 1;
|
||||
ctx->dsc.slice_height = 13;
|
||||
ctx->dsc.slice_width = 540;
|
||||
|
||||
ctx->dsc.slice_count = 1080 / ctx->dsc.slice_width;
|
||||
ctx->dsc.bits_per_component = 10;
|
||||
ctx->dsc.bits_per_pixel = 8 << 4; /* 4 fractional bits */
|
||||
ctx->dsc.block_pred_enable = true;
|
||||
|
||||
return devm_mipi_dsi_attach(dev, dsi);
|
||||
}
|
||||
|
||||
static const struct of_device_id raydium_rm69220_of_match[] = {
|
||||
{ .compatible = "boe,bf068mwm-td0" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, raydium_rm69220_of_match);
|
||||
|
||||
static struct mipi_dsi_driver raydium_rm69220_driver = {
|
||||
.probe = raydium_rm69220_probe,
|
||||
.driver = {
|
||||
.name = "panel-raydium-rm69220",
|
||||
.of_match_table = raydium_rm69220_of_match,
|
||||
},
|
||||
};
|
||||
module_mipi_dsi_driver(raydium_rm69220_driver);
|
||||
|
||||
MODULE_AUTHOR("Alexander Koskovich <akoskovich@pm.me>");
|
||||
MODULE_DESCRIPTION("DRM driver for RM69220-equipped DSI panels");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -75,15 +75,25 @@ static int rb070d30_panel_unprepare(struct drm_panel *panel)
|
|||
static int rb070d30_panel_enable(struct drm_panel *panel)
|
||||
{
|
||||
struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);
|
||||
struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
|
||||
|
||||
return mipi_dsi_dcs_exit_sleep_mode(ctx->dsi);
|
||||
mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
|
||||
return dsi_ctx.accum_err;
|
||||
}
|
||||
|
||||
static int rb070d30_panel_disable(struct drm_panel *panel)
|
||||
{
|
||||
struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);
|
||||
struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
|
||||
|
||||
return mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
|
||||
mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
|
||||
|
||||
/*
|
||||
* Returning an error would leave panel->enabled set, causing the
|
||||
* next enable to be skipped even after unprepare powers off the panel.
|
||||
* The helper above already logs any command failure.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Default timings */
|
||||
|
|
|
|||
|
|
@ -4379,6 +4379,9 @@ static const struct panel_desc raystar_rff500f_awh_dnn = {
|
|||
.width = 108,
|
||||
.height = 65,
|
||||
},
|
||||
.delay = {
|
||||
.enable = 250,
|
||||
},
|
||||
.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
|
||||
.connector_type = DRM_MODE_CONNECTOR_LVDS,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <drm/display/drm_dsc.h>
|
||||
#include <drm/display/drm_dsc_helper.h>
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_modes.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
|
|
@ -18,10 +19,24 @@
|
|||
|
||||
struct visionox_vtdr6130 {
|
||||
struct drm_panel panel;
|
||||
struct drm_dsc_config dsc;
|
||||
struct mipi_dsi_device *dsi;
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct regulator_bulk_data *supplies;
|
||||
enum drm_panel_orientation orientation;
|
||||
struct visionox_vtdr6130_desc *desc;
|
||||
};
|
||||
|
||||
struct visionox_vtdr6130_desc {
|
||||
unsigned int bpc;
|
||||
unsigned int lanes;
|
||||
unsigned long mode_flags;
|
||||
enum mipi_dsi_pixel_format format;
|
||||
|
||||
const struct drm_display_mode *modes;
|
||||
unsigned int num_modes;
|
||||
int (*init_sequence)(struct visionox_vtdr6130 *ctx);
|
||||
|
||||
struct drm_dsc_config dsc;
|
||||
};
|
||||
|
||||
static const struct regulator_bulk_data visionox_vtdr6130_supplies[] = {
|
||||
|
|
@ -45,6 +60,82 @@ static void visionox_vtdr6130_reset(struct visionox_vtdr6130 *ctx)
|
|||
usleep_range(10000, 11000);
|
||||
}
|
||||
|
||||
static int retroidpocket_rp6_on(struct visionox_vtdr6130 *ctx)
|
||||
{
|
||||
struct mipi_dsi_device *dsi = ctx->dsi;
|
||||
struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
|
||||
struct drm_dsc_picture_parameter_set pps;
|
||||
|
||||
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
|
||||
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x01);
|
||||
mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx,
|
||||
MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);
|
||||
mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, 0xff07);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x02);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x02);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6c, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x00);
|
||||
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x70, 0x11, 0x00, 0x00, 0x89,
|
||||
0x30, 0x80, 0x07, 0x80, 0x04, 0x38, 0x00,
|
||||
0x14, 0x02, 0x1c, 0x02, 0x1c, 0x02, 0x00,
|
||||
0x02, 0x25, 0x00, 0x20, 0x01, 0xd5, 0x00,
|
||||
0x07, 0x00, 0x0d, 0x05, 0x7a, 0x05, 0x16,
|
||||
0x18, 0x00, 0x10, 0xf0, 0x03, 0x0c, 0x20,
|
||||
0x00, 0x06, 0x0b, 0x0b, 0x33, 0x0e, 0x1c,
|
||||
0x2a, 0x38, 0x46, 0x54, 0x62, 0x69, 0x70,
|
||||
0x77, 0x79, 0x7b, 0x7d, 0x7e, 0x01, 0x02,
|
||||
0x01, 0x00, 0x09, 0x40, 0x09, 0xbe, 0x19,
|
||||
0xfc, 0x19, 0xfa, 0x19, 0xf8, 0x1a, 0x38,
|
||||
0x1a, 0x78, 0x1a, 0xb6, 0x2a, 0xb6, 0x2a,
|
||||
0xf4, 0x2a, 0xf4, 0x4b, 0x34, 0x63, 0x74,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
|
||||
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xaa, 0x10);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb1, 0x02, 0x15, 0x00, 0x14,
|
||||
0x00, 0x20, 0x00, 0x02, 0x16, 0x00, 0x14,
|
||||
0x07, 0xb4, 0x00, 0x02, 0x16, 0x00, 0x14,
|
||||
0x00, 0x10, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xaa, 0x14);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb2, 0x03, 0x33);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb4, 0x0a, 0x72, 0x00, 0x00,
|
||||
0x0a, 0x72, 0x00, 0x00, 0x0a, 0x72, 0x00,
|
||||
0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb5, 0x00, 0x1e, 0x1e, 0x1e,
|
||||
0x1e, 0x1e, 0x1e, 0x06, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb9, 0x00, 0x00, 0x08, 0x1e,
|
||||
0x1e, 0x1e);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbc, 0x10, 0x00, 0x00, 0x08,
|
||||
0x11, 0x1e, 0x7c, 0x1e, 0x7c, 0x1e, 0x7c);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbe, 0x10, 0x10, 0x00, 0x0c,
|
||||
0x22, 0x1e, 0x62, 0x1e, 0x62, 0x1e, 0x62);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0x80);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x13);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfd, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0x81);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf9, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0x83);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x04);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf8, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xaa, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0x00);
|
||||
|
||||
mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
|
||||
mipi_dsi_msleep(&dsi_ctx, 150);
|
||||
|
||||
mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
|
||||
mipi_dsi_msleep(&dsi_ctx, 50);
|
||||
|
||||
drm_dsc_pps_payload_pack(&pps, dsi->dsc);
|
||||
mipi_dsi_picture_parameter_set_multi(&dsi_ctx, &pps);
|
||||
mipi_dsi_compression_mode_multi(&dsi_ctx, true);
|
||||
|
||||
return dsi_ctx.accum_err;
|
||||
}
|
||||
|
||||
static int visionox_vtdr6130_on(struct visionox_vtdr6130 *ctx)
|
||||
{
|
||||
struct mipi_dsi_device *dsi = ctx->dsi;
|
||||
|
|
@ -160,7 +251,7 @@ static int visionox_vtdr6130_prepare(struct drm_panel *panel)
|
|||
|
||||
visionox_vtdr6130_reset(ctx);
|
||||
|
||||
ret = visionox_vtdr6130_on(ctx);
|
||||
ret = ctx->desc->init_sequence(ctx);
|
||||
if (ret < 0) {
|
||||
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
||||
regulator_bulk_disable(ARRAY_SIZE(visionox_vtdr6130_supplies),
|
||||
|
|
@ -185,26 +276,87 @@ static int visionox_vtdr6130_unprepare(struct drm_panel *panel)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_display_mode visionox_vtdr6130_mode = {
|
||||
.clock = (1080 + 20 + 2 + 20) * (2400 + 20 + 2 + 18) * 144 / 1000,
|
||||
.hdisplay = 1080,
|
||||
.hsync_start = 1080 + 20,
|
||||
.hsync_end = 1080 + 20 + 2,
|
||||
.htotal = 1080 + 20 + 2 + 20,
|
||||
.vdisplay = 2400,
|
||||
.vsync_start = 2400 + 20,
|
||||
.vsync_end = 2400 + 20 + 2,
|
||||
.vtotal = 2400 + 20 + 2 + 18,
|
||||
.width_mm = 71,
|
||||
.height_mm = 157,
|
||||
static const struct drm_display_mode retroidpocket_rp6_modes[] = {
|
||||
{
|
||||
.clock = (1080 + 22 + 2 + 16) * (1920 + 16 + 2 + 20) * 120 / 1000,
|
||||
.hdisplay = 1080,
|
||||
.hsync_start = 1080 + 22,
|
||||
.hsync_end = 1080 + 22 + 2,
|
||||
.htotal = 1080 + 22 + 2 + 16,
|
||||
.vdisplay = 1920,
|
||||
.vsync_start = 1920 + 16,
|
||||
.vsync_end = 1920 + 16 + 2,
|
||||
.vtotal = 1920 + 16 + 2 + 20,
|
||||
.width_mm = 69,
|
||||
.height_mm = 122,
|
||||
},
|
||||
};
|
||||
|
||||
static struct visionox_vtdr6130_desc retroidpocket_rp6_panel_desc = {
|
||||
.modes = retroidpocket_rp6_modes,
|
||||
.num_modes = ARRAY_SIZE(retroidpocket_rp6_modes),
|
||||
.bpc = 8,
|
||||
.lanes = 4,
|
||||
.format = MIPI_DSI_FMT_RGB888,
|
||||
.mode_flags = MIPI_DSI_MODE_NO_EOT_PACKET |
|
||||
MIPI_DSI_CLOCK_NON_CONTINUOUS,
|
||||
.init_sequence = retroidpocket_rp6_on,
|
||||
.dsc = {
|
||||
.dsc_version_major = 0x1,
|
||||
.dsc_version_minor = 0x1,
|
||||
.slice_height = 12,
|
||||
.slice_width = 540,
|
||||
.slice_count = 2,
|
||||
.bits_per_component = 8,
|
||||
.bits_per_pixel = 8 << 4,
|
||||
.block_pred_enable = true,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct drm_display_mode visionox_vtdr6130_modes[] = {
|
||||
{
|
||||
.clock = (1080 + 20 + 2 + 20) * (2400 + 20 + 2 + 18) * 144 / 1000,
|
||||
.hdisplay = 1080,
|
||||
.hsync_start = 1080 + 20,
|
||||
.hsync_end = 1080 + 20 + 2,
|
||||
.htotal = 1080 + 20 + 2 + 20,
|
||||
.vdisplay = 2400,
|
||||
.vsync_start = 2400 + 20,
|
||||
.vsync_end = 2400 + 20 + 2,
|
||||
.vtotal = 2400 + 20 + 2 + 18,
|
||||
.width_mm = 71,
|
||||
.height_mm = 157,
|
||||
},
|
||||
};
|
||||
|
||||
static struct visionox_vtdr6130_desc visionox_vtdr6130_panel_desc = {
|
||||
.modes = visionox_vtdr6130_modes,
|
||||
.num_modes = ARRAY_SIZE(visionox_vtdr6130_modes),
|
||||
.bpc = 8,
|
||||
.lanes = 4,
|
||||
.format = MIPI_DSI_FMT_RGB888,
|
||||
.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_NO_EOT_PACKET |
|
||||
MIPI_DSI_CLOCK_NON_CONTINUOUS,
|
||||
.init_sequence = visionox_vtdr6130_on,
|
||||
.dsc = {
|
||||
.dsc_version_major = 0x1,
|
||||
.dsc_version_minor = 0x2,
|
||||
.slice_height = 40,
|
||||
.slice_width = 540,
|
||||
.slice_count = 2,
|
||||
.bits_per_component = 8,
|
||||
.bits_per_pixel = 8 << 4,
|
||||
.block_pred_enable = true,
|
||||
},
|
||||
};
|
||||
|
||||
static int visionox_vtdr6130_get_modes(struct drm_panel *panel,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct visionox_vtdr6130 *ctx = to_visionox_vtdr6130(panel);
|
||||
struct drm_display_mode *mode;
|
||||
|
||||
mode = drm_mode_duplicate(connector->dev, &visionox_vtdr6130_mode);
|
||||
mode = drm_mode_duplicate(connector->dev, ctx->desc->modes);
|
||||
if (!mode)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -218,10 +370,18 @@ static int visionox_vtdr6130_get_modes(struct drm_panel *panel,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static enum drm_panel_orientation visionox_vtdr6130_get_orientation(struct drm_panel *panel)
|
||||
{
|
||||
struct visionox_vtdr6130 *ctx = to_visionox_vtdr6130(panel);
|
||||
|
||||
return ctx->orientation;
|
||||
}
|
||||
|
||||
static const struct drm_panel_funcs visionox_vtdr6130_panel_funcs = {
|
||||
.prepare = visionox_vtdr6130_prepare,
|
||||
.unprepare = visionox_vtdr6130_unprepare,
|
||||
.get_modes = visionox_vtdr6130_get_modes,
|
||||
.get_orientation = visionox_vtdr6130_get_orientation,
|
||||
};
|
||||
|
||||
static int visionox_vtdr6130_bl_update_status(struct backlight_device *bl)
|
||||
|
|
@ -274,25 +434,25 @@ static int visionox_vtdr6130_probe(struct mipi_dsi_device *dsi)
|
|||
return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
|
||||
"Failed to get reset-gpios\n");
|
||||
|
||||
ctx->desc = (struct visionox_vtdr6130_desc *)of_device_get_match_data(dev);
|
||||
if (!ctx->desc)
|
||||
return -ENODEV;
|
||||
|
||||
ctx->dsi = dsi;
|
||||
mipi_dsi_set_drvdata(dsi, ctx);
|
||||
|
||||
ctx->dsc.dsc_version_major = 0x1;
|
||||
ctx->dsc.dsc_version_minor = 0x2;
|
||||
ctx->dsc.slice_height = 40;
|
||||
ctx->dsc.slice_width = 540;
|
||||
ctx->dsc.slice_count = 2;
|
||||
ctx->dsc.bits_per_component = 8;
|
||||
ctx->dsc.bits_per_pixel = 8 << 4;
|
||||
ctx->dsc.block_pred_enable = true;
|
||||
|
||||
dsi->dsc = &ctx->dsc;
|
||||
dsi->lanes = 4;
|
||||
dsi->format = MIPI_DSI_FMT_RGB888;
|
||||
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_NO_EOT_PACKET |
|
||||
MIPI_DSI_CLOCK_NON_CONTINUOUS;
|
||||
dsi->dsc = &ctx->desc->dsc;
|
||||
dsi->lanes = ctx->desc->lanes;
|
||||
dsi->format = ctx->desc->format;
|
||||
dsi->mode_flags = ctx->desc->mode_flags;
|
||||
ctx->panel.prepare_prev_first = true;
|
||||
|
||||
ret = drm_of_get_panel_orientation(dev->of_node, &ctx->orientation);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to get orientation %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ctx->panel.backlight = visionox_vtdr6130_create_backlight(dsi);
|
||||
if (IS_ERR(ctx->panel.backlight))
|
||||
return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
|
||||
|
|
@ -306,7 +466,8 @@ static int visionox_vtdr6130_probe(struct mipi_dsi_device *dsi)
|
|||
}
|
||||
|
||||
static const struct of_device_id visionox_vtdr6130_of_match[] = {
|
||||
{ .compatible = "visionox,vtdr6130" },
|
||||
{ .compatible = "retroidpocket,rp6-panel", .data = &retroidpocket_rp6_panel_desc },
|
||||
{ .compatible = "visionox,vtdr6130", .data = &visionox_vtdr6130_panel_desc },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, visionox_vtdr6130_of_match);
|
||||
|
|
|
|||
|
|
@ -2,12 +2,15 @@
|
|||
/* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */
|
||||
/* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
#include "panfrost_device.h"
|
||||
#include "panfrost_devfreq.h"
|
||||
|
|
@ -34,51 +37,23 @@ static void panfrost_reset_fini(struct panfrost_device *pfdev)
|
|||
reset_control_assert(pfdev->rstc);
|
||||
}
|
||||
|
||||
static int panfrost_clk_init(struct panfrost_device *pfdev)
|
||||
static int panfrost_clks_enable(struct panfrost_device *pfdev, bool on_resume)
|
||||
{
|
||||
int err;
|
||||
unsigned long rate;
|
||||
|
||||
pfdev->clock = devm_clk_get(pfdev->base.dev, NULL);
|
||||
if (IS_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->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->base.dev, "bus");
|
||||
if (IS_ERR(pfdev->bus_clock)) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (pfdev->bus_clock) {
|
||||
rate = clk_get_rate(pfdev->bus_clock);
|
||||
dev_info(pfdev->base.dev, "bus_clock rate = %lu\n", rate);
|
||||
|
||||
err = clk_prepare_enable(pfdev->bus_clock);
|
||||
if (err)
|
||||
goto disable_clock;
|
||||
}
|
||||
|
||||
pfdev->bus_ace_clock = devm_clk_get_optional(pfdev->base.dev, "bus_ace");
|
||||
if (IS_ERR(pfdev->bus_ace_clock)) {
|
||||
err = PTR_ERR(pfdev->bus_ace_clock);
|
||||
dev_err(pfdev->base.dev, "get bus_ace_clock failed %d\n", err);
|
||||
goto disable_bus_clock;
|
||||
}
|
||||
|
||||
err = clk_prepare_enable(pfdev->bus_ace_clock);
|
||||
err = clk_prepare_enable(pfdev->bus_clock);
|
||||
if (err)
|
||||
goto disable_bus_clock;
|
||||
goto disable_clock;
|
||||
|
||||
if (on_resume) {
|
||||
err = clk_prepare_enable(pfdev->bus_ace_clock);
|
||||
if (err)
|
||||
goto disable_bus_clock;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
@ -90,13 +65,83 @@ static int panfrost_clk_init(struct panfrost_device *pfdev)
|
|||
return err;
|
||||
}
|
||||
|
||||
static void panfrost_clk_fini(struct panfrost_device *pfdev)
|
||||
static void panfrost_clks_disable(struct panfrost_device *pfdev, bool on_suspend)
|
||||
{
|
||||
clk_disable_unprepare(pfdev->bus_ace_clock);
|
||||
if (on_suspend)
|
||||
clk_disable_unprepare(pfdev->bus_ace_clock);
|
||||
clk_disable_unprepare(pfdev->bus_clock);
|
||||
clk_disable_unprepare(pfdev->clock);
|
||||
}
|
||||
|
||||
static int panfrost_clk_init(struct panfrost_device *pfdev)
|
||||
{
|
||||
unsigned long rate;
|
||||
int err;
|
||||
|
||||
pfdev->clock = devm_clk_get(pfdev->base.dev, NULL);
|
||||
if (IS_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->base.dev, "clock rate = %lu\n", rate);
|
||||
|
||||
err = clk_prepare(pfdev->clock);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
pfdev->bus_clock = devm_clk_get_optional(pfdev->base.dev, "bus");
|
||||
if (IS_ERR(pfdev->bus_clock)) {
|
||||
err = PTR_ERR(pfdev->bus_clock);
|
||||
dev_err(pfdev->base.dev, "get bus_clock failed %d\n", err);
|
||||
goto unprepare_clock;
|
||||
}
|
||||
|
||||
if (pfdev->bus_clock) {
|
||||
rate = clk_get_rate(pfdev->bus_clock);
|
||||
dev_info(pfdev->base.dev, "bus_clock rate = %lu\n", rate);
|
||||
|
||||
err = clk_prepare(pfdev->bus_clock);
|
||||
if (err)
|
||||
goto unprepare_clock;
|
||||
}
|
||||
|
||||
pfdev->bus_ace_clock = devm_clk_get_optional(pfdev->base.dev, "bus_ace");
|
||||
if (IS_ERR(pfdev->bus_ace_clock)) {
|
||||
err = PTR_ERR(pfdev->bus_ace_clock);
|
||||
dev_err(pfdev->base.dev, "get bus_ace_clock failed %d\n", err);
|
||||
goto unprepare_bus_clock;
|
||||
}
|
||||
|
||||
err = clk_prepare(pfdev->bus_ace_clock);
|
||||
if (err)
|
||||
goto unprepare_bus_clock;
|
||||
|
||||
err = panfrost_clks_enable(pfdev, true);
|
||||
if (err)
|
||||
goto unprepare_bus_ace_clock;
|
||||
|
||||
return 0;
|
||||
|
||||
unprepare_bus_ace_clock:
|
||||
clk_unprepare(pfdev->bus_ace_clock);
|
||||
unprepare_bus_clock:
|
||||
clk_unprepare(pfdev->bus_clock);
|
||||
unprepare_clock:
|
||||
clk_unprepare(pfdev->clock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void panfrost_clk_fini(struct panfrost_device *pfdev)
|
||||
{
|
||||
panfrost_clks_disable(pfdev, true);
|
||||
clk_unprepare(pfdev->bus_ace_clock);
|
||||
clk_unprepare(pfdev->bus_clock);
|
||||
clk_unprepare(pfdev->clock);
|
||||
}
|
||||
|
||||
static int panfrost_regulator_init(struct panfrost_device *pfdev)
|
||||
{
|
||||
int ret, i;
|
||||
|
|
@ -214,14 +259,14 @@ static int panfrost_pm_domain_init(struct panfrost_device *pfdev)
|
|||
|
||||
int panfrost_device_init(struct panfrost_device *pfdev)
|
||||
{
|
||||
bool device_initialised = false;
|
||||
int err;
|
||||
|
||||
mutex_init(&pfdev->sched_lock);
|
||||
INIT_LIST_HEAD(&pfdev->as_lru_list);
|
||||
pfdev->comp = of_device_get_match_data(pfdev->base.dev);
|
||||
if (!pfdev->comp)
|
||||
return -ENODEV;
|
||||
|
||||
spin_lock_init(&pfdev->as_lock);
|
||||
|
||||
spin_lock_init(&pfdev->cycle_counter.lock);
|
||||
pfdev->coherent = device_get_dma_attr(pfdev->base.dev) == DEV_DMA_COHERENT;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
mutex_init(&pfdev->debugfs.gems_lock);
|
||||
|
|
@ -280,9 +325,41 @@ int panfrost_device_init(struct panfrost_device *pfdev)
|
|||
if (err)
|
||||
goto out_job;
|
||||
|
||||
panfrost_gem_init(pfdev);
|
||||
err = panfrost_gem_init(pfdev);
|
||||
if (err)
|
||||
goto out_perfcnt;
|
||||
|
||||
device_initialised = true;
|
||||
|
||||
/* The reason we must manually set the PM status and usage counter is
|
||||
* we have just powered the device up but did not go through the PM
|
||||
* runtime resume callback, so we need to update these ourselves.
|
||||
*/
|
||||
pm_runtime_get_noresume(pfdev->base.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(&pfdev->base, 0);
|
||||
if (err < 0)
|
||||
goto err_disable_rpm;
|
||||
|
||||
pm_runtime_put_autosuspend(pfdev->base.dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_disable_rpm:
|
||||
pm_runtime_dont_use_autosuspend(pfdev->base.dev);
|
||||
pm_runtime_disable(pfdev->base.dev);
|
||||
panfrost_gem_fini(pfdev);
|
||||
out_perfcnt:
|
||||
panfrost_perfcnt_fini(pfdev);
|
||||
out_job:
|
||||
panfrost_jm_fini(pfdev);
|
||||
out_mmu:
|
||||
|
|
@ -299,11 +376,23 @@ int panfrost_device_init(struct panfrost_device *pfdev)
|
|||
panfrost_reset_fini(pfdev);
|
||||
out_pm_domain:
|
||||
panfrost_pm_domain_fini(pfdev);
|
||||
|
||||
if (device_initialised) {
|
||||
pm_runtime_set_suspended(pfdev->base.dev);
|
||||
pm_runtime_put_noidle(pfdev->base.dev);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void panfrost_device_fini(struct panfrost_device *pfdev)
|
||||
{
|
||||
drm_WARN_ON(&pfdev->base, pm_runtime_get_sync(pfdev->base.dev) < 0);
|
||||
|
||||
pm_runtime_dont_use_autosuspend(pfdev->base.dev);
|
||||
pm_runtime_disable(pfdev->base.dev);
|
||||
|
||||
panfrost_gem_fini(pfdev);
|
||||
panfrost_perfcnt_fini(pfdev);
|
||||
panfrost_jm_fini(pfdev);
|
||||
panfrost_mmu_fini(pfdev);
|
||||
|
|
@ -313,6 +402,9 @@ void panfrost_device_fini(struct panfrost_device *pfdev)
|
|||
panfrost_clk_fini(pfdev);
|
||||
panfrost_reset_fini(pfdev);
|
||||
panfrost_pm_domain_fini(pfdev);
|
||||
|
||||
pm_runtime_set_suspended(pfdev->base.dev);
|
||||
pm_runtime_put_noidle(pfdev->base.dev);
|
||||
}
|
||||
|
||||
#define PANFROST_EXCEPTION(id) \
|
||||
|
|
@ -417,6 +509,8 @@ bool panfrost_exception_needs_reset(const struct panfrost_device *pfdev,
|
|||
|
||||
void panfrost_device_reset(struct panfrost_device *pfdev, bool enable_job_int)
|
||||
{
|
||||
guard(rwsem_write)(&pfdev->reset.lock);
|
||||
|
||||
panfrost_gpu_soft_reset(pfdev);
|
||||
|
||||
panfrost_gpu_power_on(pfdev);
|
||||
|
|
@ -425,6 +519,8 @@ void panfrost_device_reset(struct panfrost_device *pfdev, bool enable_job_int)
|
|||
panfrost_jm_reset_interrupts(pfdev);
|
||||
if (enable_job_int)
|
||||
panfrost_jm_enable_interrupts(pfdev);
|
||||
|
||||
panfrost_perfcnt_reset(pfdev);
|
||||
}
|
||||
|
||||
static int panfrost_device_runtime_resume(struct device *dev)
|
||||
|
|
@ -437,34 +533,17 @@ static int panfrost_device_runtime_resume(struct device *dev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_enable(pfdev->clock);
|
||||
if (ret)
|
||||
goto err_clk;
|
||||
|
||||
ret = clk_enable(pfdev->bus_clock);
|
||||
if (ret)
|
||||
goto err_bus_clk;
|
||||
|
||||
ret = clk_enable(pfdev->bus_ace_clock);
|
||||
if (ret)
|
||||
goto err_bus_ace_clk;
|
||||
ret = panfrost_clks_enable(pfdev, true);
|
||||
if (ret) {
|
||||
reset_control_assert(pfdev->rstc);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
panfrost_device_reset(pfdev, true);
|
||||
panfrost_devfreq_resume(pfdev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_bus_ace_clk:
|
||||
if (pfdev->comp->pm_features & BIT(GPU_PM_RT))
|
||||
clk_disable(pfdev->bus_clock);
|
||||
err_bus_clk:
|
||||
if (pfdev->comp->pm_features & BIT(GPU_PM_RT))
|
||||
clk_disable(pfdev->clock);
|
||||
err_clk:
|
||||
if (pfdev->comp->pm_features & BIT(GPU_PM_RT))
|
||||
reset_control_assert(pfdev->rstc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int panfrost_device_runtime_suspend(struct device *dev)
|
||||
|
|
@ -481,9 +560,7 @@ static int panfrost_device_runtime_suspend(struct device *dev)
|
|||
panfrost_gpu_power_off(pfdev);
|
||||
|
||||
if (pfdev->comp->pm_features & BIT(GPU_PM_RT)) {
|
||||
clk_disable(pfdev->bus_ace_clock);
|
||||
clk_disable(pfdev->bus_clock);
|
||||
clk_disable(pfdev->clock);
|
||||
panfrost_clks_disable(pfdev, true);
|
||||
reset_control_assert(pfdev->rstc);
|
||||
}
|
||||
|
||||
|
|
@ -507,15 +584,9 @@ static int panfrost_device_resume(struct device *dev)
|
|||
}
|
||||
|
||||
if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS)) {
|
||||
ret = clk_enable(pfdev->clock);
|
||||
ret = panfrost_clks_enable(pfdev, false);
|
||||
if (ret)
|
||||
goto err_clk;
|
||||
|
||||
if (pfdev->bus_clock) {
|
||||
ret = clk_enable(pfdev->bus_clock);
|
||||
if (ret)
|
||||
goto err_bus_clk;
|
||||
}
|
||||
}
|
||||
|
||||
ret = pm_runtime_force_resume(dev);
|
||||
|
|
@ -525,11 +596,8 @@ static int panfrost_device_resume(struct device *dev)
|
|||
return 0;
|
||||
|
||||
err_resume:
|
||||
if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS) && pfdev->bus_clock)
|
||||
clk_disable(pfdev->bus_clock);
|
||||
err_bus_clk:
|
||||
if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS))
|
||||
clk_disable(pfdev->clock);
|
||||
panfrost_clks_disable(pfdev, false);
|
||||
err_clk:
|
||||
if (pfdev->comp->pm_features & BIT(GPU_PM_VREG_OFF))
|
||||
dev_pm_opp_set_opp(dev, NULL);
|
||||
|
|
@ -545,12 +613,8 @@ static int panfrost_device_suspend(struct device *dev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS)) {
|
||||
if (pfdev->bus_clock)
|
||||
clk_disable(pfdev->bus_clock);
|
||||
|
||||
clk_disable(pfdev->clock);
|
||||
}
|
||||
if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS))
|
||||
panfrost_clks_disable(pfdev, false);
|
||||
|
||||
if (pfdev->comp->pm_features & BIT(GPU_PM_VREG_OFF))
|
||||
dev_pm_opp_set_opp(dev, NULL);
|
||||
|
|
@ -562,3 +626,56 @@ EXPORT_GPL_DEV_PM_OPS(panfrost_pm_ops) = {
|
|||
RUNTIME_PM_OPS(panfrost_device_runtime_suspend, panfrost_device_runtime_resume, NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(panfrost_device_suspend, panfrost_device_resume)
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static int reset_get(void *data, u64 *val)
|
||||
{
|
||||
struct panfrost_device *pfdev =
|
||||
container_of(data, struct panfrost_device, base);
|
||||
|
||||
*val = atomic_read(&pfdev->reset.pending);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reset_set(void *data, u64 val)
|
||||
{
|
||||
struct panfrost_device *pfdev =
|
||||
container_of(data, struct panfrost_device, base);
|
||||
int ret;
|
||||
|
||||
if (val != 1)
|
||||
return -EINVAL;
|
||||
|
||||
ret = pm_runtime_get_if_active(pfdev->base.dev);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
panfrost_device_schedule_reset(pfdev);
|
||||
flush_work(&pfdev->reset.work);
|
||||
|
||||
/* ret < 0 means runtime PM for the device is disabled, so we
|
||||
* only need to return the PM reference in the opposite case
|
||||
*/
|
||||
if (ret > 0)
|
||||
pm_runtime_put(pfdev->base.dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(panfrost_reset_debugfs_fops,
|
||||
reset_get, reset_set,
|
||||
"0x%08llx\n");
|
||||
|
||||
static void panfrost_reset_debugfs_init(struct drm_minor *minor)
|
||||
{
|
||||
debugfs_create_file("reset", 0600, minor->debugfs_root,
|
||||
minor->dev, &panfrost_reset_debugfs_fops);
|
||||
}
|
||||
|
||||
void panfrost_device_debugfs_init(struct drm_minor *minor)
|
||||
{
|
||||
panfrost_gem_debugfs_init(minor);
|
||||
panfrost_sched_debugfs_init(minor);
|
||||
panfrost_reset_debugfs_init(minor);
|
||||
}
|
||||
#endif // CONFIG_DEBUG_FS
|
||||
|
|
|
|||
|
|
@ -165,6 +165,7 @@ struct panfrost_device {
|
|||
struct {
|
||||
struct workqueue_struct *wq;
|
||||
struct work_struct work;
|
||||
struct rw_semaphore lock;
|
||||
atomic_t pending;
|
||||
} reset;
|
||||
|
||||
|
|
@ -341,4 +342,8 @@ panfrost_device_schedule_reset(struct panfrost_device *pfdev)
|
|||
queue_work(pfdev->reset.wq, &pfdev->reset.work);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
void panfrost_device_debugfs_init(struct drm_minor *minor);
|
||||
#endif // CONFIG_DEBUG_FS
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
#include <drm/drm_timeout.h>
|
||||
|
||||
#include "panfrost_device.h"
|
||||
#include "panfrost_drv.h"
|
||||
#include "panfrost_gem.h"
|
||||
#include "panfrost_mmu.h"
|
||||
#include "panfrost_job.h"
|
||||
|
|
@ -42,9 +41,12 @@ static int panfrost_ioctl_query_timestamp(struct panfrost_device *pfdev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
panfrost_cycle_counter_get(pfdev);
|
||||
*arg = panfrost_timestamp_read(pfdev);
|
||||
panfrost_cycle_counter_put(pfdev);
|
||||
/* We should not read timestamp register while the GPU is being reset */
|
||||
scoped_guard(rwsem_read, &pfdev->reset.lock) {
|
||||
panfrost_cycle_counter_get(pfdev);
|
||||
*arg = panfrost_timestamp_read(pfdev);
|
||||
panfrost_cycle_counter_put(pfdev);
|
||||
}
|
||||
|
||||
pm_runtime_put(pfdev->base.dev);
|
||||
return 0;
|
||||
|
|
@ -793,133 +795,6 @@ static const struct file_operations panfrost_drm_driver_fops = {
|
|||
.show_fdinfo = drm_show_fdinfo,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static int panthor_gems_show(struct seq_file *m, void *data)
|
||||
{
|
||||
struct drm_info_node *node = m->private;
|
||||
struct panfrost_device *pfdev = to_panfrost_device(node->minor->dev);
|
||||
|
||||
panfrost_gem_debugfs_print_bos(pfdev, m);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void show_panfrost_jm_ctx(struct panfrost_jm_ctx *jm_ctx, u32 handle,
|
||||
struct seq_file *m)
|
||||
{
|
||||
struct drm_device *ddev = ((struct drm_info_node *)m->private)->minor->dev;
|
||||
const char *prio = "UNKNOWN";
|
||||
|
||||
static const char * const prios[] = {
|
||||
[DRM_SCHED_PRIORITY_HIGH] = "HIGH",
|
||||
[DRM_SCHED_PRIORITY_NORMAL] = "NORMAL",
|
||||
[DRM_SCHED_PRIORITY_LOW] = "LOW",
|
||||
};
|
||||
|
||||
if (jm_ctx->slot_entity[0].priority !=
|
||||
jm_ctx->slot_entity[1].priority)
|
||||
drm_warn(ddev, "Slot priorities should be the same in a single context");
|
||||
|
||||
if (jm_ctx->slot_entity[0].priority < ARRAY_SIZE(prios))
|
||||
prio = prios[jm_ctx->slot_entity[0].priority];
|
||||
|
||||
seq_printf(m, " JM context %u: priority %s\n", handle, prio);
|
||||
}
|
||||
|
||||
static int show_file_jm_ctxs(struct panfrost_file_priv *pfile,
|
||||
struct seq_file *m)
|
||||
{
|
||||
struct panfrost_jm_ctx *jm_ctx;
|
||||
unsigned long i;
|
||||
|
||||
xa_lock(&pfile->jm_ctxs);
|
||||
xa_for_each(&pfile->jm_ctxs, i, jm_ctx) {
|
||||
jm_ctx = panfrost_jm_ctx_get(jm_ctx);
|
||||
xa_unlock(&pfile->jm_ctxs);
|
||||
show_panfrost_jm_ctx(jm_ctx, i, m);
|
||||
panfrost_jm_ctx_put(jm_ctx);
|
||||
xa_lock(&pfile->jm_ctxs);
|
||||
}
|
||||
xa_unlock(&pfile->jm_ctxs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct drm_info_list panthor_debugfs_list[] = {
|
||||
{"gems",
|
||||
panthor_gems_show, 0, NULL},
|
||||
};
|
||||
|
||||
static int panthor_gems_debugfs_init(struct drm_minor *minor)
|
||||
{
|
||||
drm_debugfs_create_files(panthor_debugfs_list,
|
||||
ARRAY_SIZE(panthor_debugfs_list),
|
||||
minor->debugfs_root, minor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int show_each_file(struct seq_file *m, void *arg)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *)m->private;
|
||||
struct drm_device *ddev = node->minor->dev;
|
||||
int (*show)(struct panfrost_file_priv *, struct seq_file *) =
|
||||
node->info_ent->data;
|
||||
struct drm_file *file;
|
||||
int ret;
|
||||
|
||||
ret = mutex_lock_interruptible(&ddev->filelist_mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
list_for_each_entry(file, &ddev->filelist, lhead) {
|
||||
struct task_struct *task;
|
||||
struct panfrost_file_priv *pfile = file->driver_priv;
|
||||
struct pid *pid;
|
||||
|
||||
/*
|
||||
* Although we have a valid reference on file->pid, that does
|
||||
* not guarantee that the task_struct who called get_pid() is
|
||||
* still alive (e.g. get_pid(current) => fork() => exit()).
|
||||
* Therefore, we need to protect this ->comm access using RCU.
|
||||
*/
|
||||
rcu_read_lock();
|
||||
pid = rcu_dereference(file->pid);
|
||||
task = pid_task(pid, PIDTYPE_TGID);
|
||||
seq_printf(m, "client_id %8llu pid %8d command %s:\n",
|
||||
file->client_id, pid_nr(pid),
|
||||
task ? task->comm : "<unknown>");
|
||||
rcu_read_unlock();
|
||||
|
||||
ret = show(pfile, m);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
seq_puts(m, "\n");
|
||||
}
|
||||
|
||||
mutex_unlock(&ddev->filelist_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct drm_info_list panfrost_sched_debugfs_list[] = {
|
||||
{ "sched_ctxs", show_each_file, 0, show_file_jm_ctxs },
|
||||
};
|
||||
|
||||
static void panfrost_sched_debugfs_init(struct drm_minor *minor)
|
||||
{
|
||||
drm_debugfs_create_files(panfrost_sched_debugfs_list,
|
||||
ARRAY_SIZE(panfrost_sched_debugfs_list),
|
||||
minor->debugfs_root, minor);
|
||||
}
|
||||
|
||||
static void panfrost_debugfs_init(struct drm_minor *minor)
|
||||
{
|
||||
panthor_gems_debugfs_init(minor);
|
||||
panfrost_sched_debugfs_init(minor);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Panfrost driver version:
|
||||
* - 1.0 - initial interface
|
||||
|
|
@ -933,6 +808,7 @@ static void panfrost_debugfs_init(struct drm_minor *minor)
|
|||
* - 1.6 - adds PANFROST_BO_MAP_WB, PANFROST_IOCTL_SYNC_BO,
|
||||
* PANFROST_IOCTL_QUERY_BO_INFO and
|
||||
* DRM_PANFROST_PARAM_SELECTED_COHERENCY
|
||||
* - 1.7 - adds PERFCNT_DUMP state field
|
||||
*/
|
||||
static const struct drm_driver panfrost_drm_driver = {
|
||||
.driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ,
|
||||
|
|
@ -945,26 +821,19 @@ static const struct drm_driver panfrost_drm_driver = {
|
|||
.name = "panfrost",
|
||||
.desc = "panfrost DRM",
|
||||
.major = 1,
|
||||
.minor = 6,
|
||||
.minor = 7,
|
||||
|
||||
.gem_create_object = panfrost_gem_create_object,
|
||||
.gem_prime_import = panfrost_gem_prime_import,
|
||||
.gem_prime_import_sg_table = panfrost_gem_prime_import_sg_table,
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
.debugfs_init = panfrost_debugfs_init,
|
||||
.debugfs_init = panfrost_device_debugfs_init,
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||||
bool panfrost_transparent_hugepage = true;
|
||||
module_param_named(transparent_hugepage, panfrost_transparent_hugepage, bool, 0400);
|
||||
MODULE_PARM_DESC(transparent_hugepage, "Use a dedicated tmpfs mount point with Transparent Hugepage enabled (true = default)");
|
||||
#endif
|
||||
|
||||
static int panfrost_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct panfrost_device *pfdev;
|
||||
int err;
|
||||
|
||||
pfdev = devm_drm_dev_alloc(&pdev->dev, &panfrost_drm_driver,
|
||||
struct panfrost_device, base);
|
||||
|
|
@ -973,50 +842,7 @@ static int panfrost_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, pfdev);
|
||||
|
||||
pfdev->comp = of_device_get_match_data(&pdev->dev);
|
||||
if (!pfdev->comp)
|
||||
return -ENODEV;
|
||||
|
||||
pfdev->coherent = device_get_dma_attr(&pdev->dev) == DEV_DMA_COHERENT;
|
||||
|
||||
mutex_init(&pfdev->shrinker_lock);
|
||||
INIT_LIST_HEAD(&pfdev->shrinker_list);
|
||||
|
||||
err = panfrost_device_init(pfdev);
|
||||
if (err) {
|
||||
if (err != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "Fatal error during GPU init\n");
|
||||
goto err_out0;
|
||||
}
|
||||
|
||||
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(&pfdev->base, 0);
|
||||
if (err < 0)
|
||||
goto err_out1;
|
||||
|
||||
err = panfrost_gem_shrinker_init(&pfdev->base);
|
||||
if (err)
|
||||
goto err_out2;
|
||||
|
||||
return 0;
|
||||
|
||||
err_out2:
|
||||
drm_dev_unregister(&pfdev->base);
|
||||
err_out1:
|
||||
pm_runtime_disable(pfdev->base.dev);
|
||||
panfrost_device_fini(pfdev);
|
||||
pm_runtime_set_suspended(pfdev->base.dev);
|
||||
err_out0:
|
||||
return err;
|
||||
return panfrost_device_init(pfdev);
|
||||
}
|
||||
|
||||
static void panfrost_remove(struct platform_device *pdev)
|
||||
|
|
@ -1024,12 +850,8 @@ static void panfrost_remove(struct platform_device *pdev)
|
|||
struct panfrost_device *pfdev = platform_get_drvdata(pdev);
|
||||
|
||||
drm_dev_unregister(&pfdev->base);
|
||||
panfrost_gem_shrinker_cleanup(&pfdev->base);
|
||||
|
||||
pm_runtime_get_sync(pfdev->base.dev);
|
||||
pm_runtime_disable(pfdev->base.dev);
|
||||
panfrost_device_fini(pfdev);
|
||||
pm_runtime_set_suspended(pfdev->base.dev);
|
||||
}
|
||||
|
||||
static ssize_t profiling_show(struct device *dev,
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 or MIT */
|
||||
/* Copyright 2025 Amazon.com, Inc. or its affiliates */
|
||||
|
||||
#ifndef __PANFROST_DRV_H__
|
||||
#define __PANFROST_DRV_H__
|
||||
|
||||
extern bool panfrost_transparent_hugepage;
|
||||
|
||||
#endif
|
||||
|
|
@ -121,6 +121,8 @@ enum panfrost_hw_feature {
|
|||
BIT_ULL(HW_FEATURE_IDVS_GROUP_SIZE) | \
|
||||
BIT_ULL(HW_FEATURE_CLEAN_ONLY_SAFE))
|
||||
|
||||
#define hw_features_g68 hw_features_g57
|
||||
|
||||
static inline bool panfrost_has_hw_feature(struct panfrost_device *pfdev,
|
||||
enum panfrost_hw_feature feat)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,26 +9,38 @@
|
|||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <drm/panfrost_drm.h>
|
||||
#include <drm/drm_debugfs.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include "panfrost_device.h"
|
||||
#include "panfrost_drv.h"
|
||||
#include "panfrost_gem.h"
|
||||
#include "panfrost_mmu.h"
|
||||
|
||||
void panfrost_gem_init(struct panfrost_device *pfdev)
|
||||
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||||
static bool panfrost_transparent_hugepage = true;
|
||||
module_param_named(transparent_hugepage, panfrost_transparent_hugepage, bool, 0400);
|
||||
MODULE_PARM_DESC(transparent_hugepage, "Use a dedicated tmpfs mount point with Transparent Hugepage enabled (true = default)");
|
||||
#else
|
||||
#define panfrost_transparent_hugepage false
|
||||
#endif
|
||||
|
||||
int panfrost_gem_init(struct panfrost_device *pfdev)
|
||||
{
|
||||
int err;
|
||||
if (panfrost_transparent_hugepage) {
|
||||
int err = drm_gem_huge_mnt_create(&pfdev->base, "within_size");
|
||||
|
||||
if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) &&
|
||||
!panfrost_transparent_hugepage)
|
||||
return;
|
||||
if (err)
|
||||
drm_warn(&pfdev->base,
|
||||
"Can't use Transparent Hugepage (%d)\n", err);
|
||||
else
|
||||
drm_info(&pfdev->base, "Using Transparent Hugepage\n");
|
||||
}
|
||||
|
||||
err = drm_gem_huge_mnt_create(&pfdev->base, "within_size");
|
||||
if (drm_gem_get_huge_mnt(&pfdev->base))
|
||||
drm_info(&pfdev->base, "Using Transparent Hugepage\n");
|
||||
else if (err)
|
||||
drm_warn(&pfdev->base, "Can't use Transparent Hugepage (%d)\n",
|
||||
err);
|
||||
return panfrost_gem_shrinker_init(pfdev);
|
||||
}
|
||||
|
||||
void panfrost_gem_fini(struct panfrost_device *pfdev)
|
||||
{
|
||||
panfrost_gem_shrinker_fini(pfdev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
|
@ -724,8 +736,8 @@ static void panfrost_gem_debugfs_bo_print(struct panfrost_gem_object *bo,
|
|||
totals->reclaimable += resident_size;
|
||||
}
|
||||
|
||||
void panfrost_gem_debugfs_print_bos(struct panfrost_device *pfdev,
|
||||
struct seq_file *m)
|
||||
static void panfrost_gem_debugfs_print_bos(struct panfrost_device *pfdev,
|
||||
struct seq_file *m)
|
||||
{
|
||||
struct gem_size_totals totals = {0};
|
||||
struct panfrost_gem_object *bo;
|
||||
|
|
@ -745,4 +757,28 @@ void panfrost_gem_debugfs_print_bos(struct panfrost_device *pfdev,
|
|||
seq_printf(m, "Total size: %zd, Total resident: %zd, Total reclaimable: %zd\n",
|
||||
totals.size, totals.resident, totals.reclaimable);
|
||||
}
|
||||
|
||||
static int panfrost_gems_show(struct seq_file *m, void *data)
|
||||
{
|
||||
struct drm_info_node *node = m->private;
|
||||
struct panfrost_device *pfdev = to_panfrost_device(node->minor->dev);
|
||||
|
||||
panfrost_gem_debugfs_print_bos(pfdev, m);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct drm_info_list panfrost_debugfs_list[] = {
|
||||
{"gems",
|
||||
panfrost_gems_show, 0, NULL},
|
||||
};
|
||||
|
||||
int panfrost_gem_debugfs_init(struct drm_minor *minor)
|
||||
{
|
||||
drm_debugfs_create_files(panfrost_debugfs_list,
|
||||
ARRAY_SIZE(panfrost_debugfs_list),
|
||||
minor->debugfs_root, minor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -129,7 +129,8 @@ drm_mm_node_to_panfrost_mapping(struct drm_mm_node *node)
|
|||
return container_of(node, struct panfrost_gem_mapping, mmnode);
|
||||
}
|
||||
|
||||
void panfrost_gem_init(struct panfrost_device *pfdev);
|
||||
int panfrost_gem_init(struct panfrost_device *pfdev);
|
||||
void panfrost_gem_fini(struct panfrost_device *pfdev);
|
||||
|
||||
struct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t size);
|
||||
|
||||
|
|
@ -154,8 +155,8 @@ panfrost_gem_mapping_get(struct panfrost_gem_object *bo,
|
|||
void panfrost_gem_mapping_put(struct panfrost_gem_mapping *mapping);
|
||||
void panfrost_gem_teardown_mappings_locked(struct panfrost_gem_object *bo);
|
||||
|
||||
int panfrost_gem_shrinker_init(struct drm_device *dev);
|
||||
void panfrost_gem_shrinker_cleanup(struct drm_device *dev);
|
||||
int panfrost_gem_shrinker_init(struct panfrost_device *pfdev);
|
||||
void panfrost_gem_shrinker_fini(struct panfrost_device *pfdev);
|
||||
|
||||
void panfrost_gem_set_label(struct drm_gem_object *obj, const char *label);
|
||||
int panfrost_gem_sync(struct drm_gem_object *obj, u32 type,
|
||||
|
|
@ -163,8 +164,7 @@ int panfrost_gem_sync(struct drm_gem_object *obj, u32 type,
|
|||
void panfrost_gem_internal_set_label(struct drm_gem_object *obj, const char *label);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
void panfrost_gem_debugfs_print_bos(struct panfrost_device *pfdev,
|
||||
struct seq_file *m);
|
||||
int panfrost_gem_debugfs_init(struct drm_minor *minor);
|
||||
#endif
|
||||
|
||||
#endif /* __PANFROST_GEM_H__ */
|
||||
|
|
|
|||
|
|
@ -95,9 +95,10 @@ panfrost_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc)
|
|||
*
|
||||
* This function registers and sets up the panfrost shrinker.
|
||||
*/
|
||||
int panfrost_gem_shrinker_init(struct drm_device *dev)
|
||||
int panfrost_gem_shrinker_init(struct panfrost_device *pfdev)
|
||||
{
|
||||
struct panfrost_device *pfdev = to_panfrost_device(dev);
|
||||
mutex_init(&pfdev->shrinker_lock);
|
||||
INIT_LIST_HEAD(&pfdev->shrinker_list);
|
||||
|
||||
pfdev->shrinker = shrinker_alloc(0, "drm-panfrost");
|
||||
if (!pfdev->shrinker)
|
||||
|
|
@ -118,10 +119,8 @@ int panfrost_gem_shrinker_init(struct drm_device *dev)
|
|||
*
|
||||
* This function unregisters the panfrost shrinker.
|
||||
*/
|
||||
void panfrost_gem_shrinker_cleanup(struct drm_device *dev)
|
||||
void panfrost_gem_shrinker_fini(struct panfrost_device *pfdev)
|
||||
{
|
||||
struct panfrost_device *pfdev = to_panfrost_device(dev);
|
||||
|
||||
if (pfdev->shrinker)
|
||||
shrinker_free(pfdev->shrinker);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -242,6 +242,9 @@ static const struct panfrost_model gpu_models[] = {
|
|||
/* MediaTek MT8188 Mali-G57 MC3 */
|
||||
GPU_MODEL(g57, 0x9093,
|
||||
GPU_REV(g57, 0, 0)),
|
||||
|
||||
GPU_MODEL(g68, 0x9004,
|
||||
GPU_REV(g68, 1, 0), GPU_REV(g68, 1, 1)),
|
||||
{0},
|
||||
};
|
||||
|
||||
|
|
@ -516,6 +519,8 @@ int panfrost_gpu_init(struct panfrost_device *pfdev)
|
|||
{
|
||||
int err;
|
||||
|
||||
spin_lock_init(&pfdev->cycle_counter.lock);
|
||||
|
||||
err = panfrost_gpu_soft_reset(pfdev);
|
||||
if (err)
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -265,6 +265,14 @@ enum panfrost_hw_issue {
|
|||
#define hw_issues_g57_r0p0 (\
|
||||
BIT_ULL(HW_ISSUE_TTRX_3485))
|
||||
|
||||
#define hw_issues_g68 (\
|
||||
BIT_ULL(HW_ISSUE_TTRX_2968_TTRX_3162))
|
||||
|
||||
#define hw_issues_g68_r1p0 (\
|
||||
BIT_ULL(HW_ISSUE_TTRX_3485))
|
||||
|
||||
#define hw_issues_g68_r1p1 0
|
||||
|
||||
static inline bool panfrost_has_hw_issue(const struct panfrost_device *pfdev,
|
||||
enum panfrost_hw_issue issue)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/dma-resv.h>
|
||||
#include <drm/drm_debugfs.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/gpu_scheduler.h>
|
||||
#include <drm/panfrost_drm.h>
|
||||
|
||||
|
|
@ -874,6 +876,8 @@ int panfrost_jm_init(struct panfrost_device *pfdev)
|
|||
|
||||
INIT_WORK(&pfdev->reset.work, panfrost_reset_work);
|
||||
spin_lock_init(&js->job_lock);
|
||||
mutex_init(&pfdev->sched_lock);
|
||||
init_rwsem(&pfdev->reset.lock);
|
||||
|
||||
js->irq = platform_get_irq_byname(to_platform_device(pfdev->base.dev), "job");
|
||||
if (js->irq < 0)
|
||||
|
|
@ -929,7 +933,7 @@ void panfrost_jm_fini(struct panfrost_device *pfdev)
|
|||
drm_sched_fini(&js->queue[j].sched);
|
||||
}
|
||||
|
||||
cancel_work_sync(&pfdev->reset.work);
|
||||
disable_work_sync(&pfdev->reset.work);
|
||||
destroy_workqueue(pfdev->reset.wq);
|
||||
}
|
||||
|
||||
|
|
@ -1137,3 +1141,100 @@ int panfrost_jm_ctx_destroy(struct drm_file *file, u32 handle)
|
|||
panfrost_jm_ctx_put(jm_ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static void show_panfrost_jm_ctx(struct panfrost_jm_ctx *jm_ctx, u32 handle,
|
||||
struct seq_file *m)
|
||||
{
|
||||
struct drm_device *ddev = ((struct drm_info_node *)m->private)->minor->dev;
|
||||
const char *prio = "UNKNOWN";
|
||||
|
||||
static const char * const prios[] = {
|
||||
[DRM_SCHED_PRIORITY_HIGH] = "HIGH",
|
||||
[DRM_SCHED_PRIORITY_NORMAL] = "NORMAL",
|
||||
[DRM_SCHED_PRIORITY_LOW] = "LOW",
|
||||
};
|
||||
|
||||
if (jm_ctx->slot_entity[0].priority !=
|
||||
jm_ctx->slot_entity[1].priority)
|
||||
drm_warn(ddev, "Slot priorities should be the same in a single context");
|
||||
|
||||
if (jm_ctx->slot_entity[0].priority < ARRAY_SIZE(prios))
|
||||
prio = prios[jm_ctx->slot_entity[0].priority];
|
||||
|
||||
seq_printf(m, " JM context %u: priority %s\n", handle, prio);
|
||||
}
|
||||
|
||||
static int show_file_jm_ctxs(struct panfrost_file_priv *pfile,
|
||||
struct seq_file *m)
|
||||
{
|
||||
struct panfrost_jm_ctx *jm_ctx;
|
||||
unsigned long i;
|
||||
|
||||
xa_lock(&pfile->jm_ctxs);
|
||||
xa_for_each(&pfile->jm_ctxs, i, jm_ctx) {
|
||||
jm_ctx = panfrost_jm_ctx_get(jm_ctx);
|
||||
xa_unlock(&pfile->jm_ctxs);
|
||||
show_panfrost_jm_ctx(jm_ctx, i, m);
|
||||
panfrost_jm_ctx_put(jm_ctx);
|
||||
xa_lock(&pfile->jm_ctxs);
|
||||
}
|
||||
xa_unlock(&pfile->jm_ctxs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int show_each_file(struct seq_file *m, void *arg)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *)m->private;
|
||||
struct drm_device *ddev = node->minor->dev;
|
||||
int (*show)(struct panfrost_file_priv *, struct seq_file *) =
|
||||
node->info_ent->data;
|
||||
struct drm_file *file;
|
||||
int ret;
|
||||
|
||||
ret = mutex_lock_interruptible(&ddev->filelist_mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
list_for_each_entry(file, &ddev->filelist, lhead) {
|
||||
struct task_struct *task;
|
||||
struct panfrost_file_priv *pfile = file->driver_priv;
|
||||
struct pid *pid;
|
||||
|
||||
/*
|
||||
* Although we have a valid reference on file->pid, that does
|
||||
* not guarantee that the task_struct who called get_pid() is
|
||||
* still alive (e.g. get_pid(current) => fork() => exit()).
|
||||
* Therefore, we need to protect this ->comm access using RCU.
|
||||
*/
|
||||
rcu_read_lock();
|
||||
pid = rcu_dereference(file->pid);
|
||||
task = pid_task(pid, PIDTYPE_TGID);
|
||||
seq_printf(m, "client_id %8llu pid %8d command %s:\n",
|
||||
file->client_id, pid_nr(pid),
|
||||
task ? task->comm : "<unknown>");
|
||||
rcu_read_unlock();
|
||||
|
||||
ret = show(pfile, m);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
seq_puts(m, "\n");
|
||||
}
|
||||
|
||||
mutex_unlock(&ddev->filelist_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct drm_info_list panfrost_sched_debugfs_list[] = {
|
||||
{ "sched_ctxs", show_each_file, 0, show_file_jm_ctxs },
|
||||
};
|
||||
|
||||
void panfrost_sched_debugfs_init(struct drm_minor *minor)
|
||||
{
|
||||
drm_debugfs_create_files(panfrost_sched_debugfs_list,
|
||||
ARRAY_SIZE(panfrost_sched_debugfs_list),
|
||||
minor->debugfs_root, minor);
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -74,4 +74,8 @@ 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);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
void panfrost_sched_debugfs_init(struct drm_minor *minor);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -336,6 +336,12 @@ void panfrost_mmu_as_put(struct panfrost_device *pfdev, struct panfrost_mmu *mmu
|
|||
WARN_ON(atomic_read(&mmu->as_count) < 0);
|
||||
}
|
||||
|
||||
static void panfrost_mmu_enable_interrupts(struct panfrost_device *pfdev)
|
||||
{
|
||||
mmu_write(pfdev, MMU_INT_CLEAR, ~0);
|
||||
mmu_write(pfdev, MMU_INT_MASK, ~0);
|
||||
}
|
||||
|
||||
void panfrost_mmu_reset(struct panfrost_device *pfdev)
|
||||
{
|
||||
struct panfrost_mmu *mmu, *mmu_tmp;
|
||||
|
|
@ -355,8 +361,7 @@ void panfrost_mmu_reset(struct panfrost_device *pfdev)
|
|||
|
||||
spin_unlock(&pfdev->as_lock);
|
||||
|
||||
mmu_write(pfdev, MMU_INT_CLEAR, ~0);
|
||||
mmu_write(pfdev, MMU_INT_MASK, ~0);
|
||||
panfrost_mmu_enable_interrupts(pfdev);
|
||||
}
|
||||
|
||||
static size_t get_pgsize(u64 addr, size_t size, size_t *count)
|
||||
|
|
@ -955,6 +960,9 @@ int panfrost_mmu_init(struct panfrost_device *pfdev)
|
|||
{
|
||||
int err;
|
||||
|
||||
INIT_LIST_HEAD(&pfdev->as_lru_list);
|
||||
spin_lock_init(&pfdev->as_lock);
|
||||
|
||||
pfdev->mmu_irq = platform_get_irq_byname(to_platform_device(pfdev->base.dev), "mmu");
|
||||
if (pfdev->mmu_irq < 0)
|
||||
return pfdev->mmu_irq;
|
||||
|
|
@ -970,6 +978,8 @@ int panfrost_mmu_init(struct panfrost_device *pfdev)
|
|||
return err;
|
||||
}
|
||||
|
||||
panfrost_mmu_enable_interrupts(pfdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright 2019 Collabora Ltd */
|
||||
|
||||
#include "asm-generic/errno-base.h"
|
||||
#include <linux/completion.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/iosys-map.h>
|
||||
|
|
@ -11,6 +12,7 @@
|
|||
#include <drm/drm_file.h>
|
||||
#include <drm/drm_gem_shmem_helper.h>
|
||||
#include <drm/panfrost_drm.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
#include "panfrost_device.h"
|
||||
#include "panfrost_features.h"
|
||||
|
|
@ -28,13 +30,33 @@
|
|||
|
||||
struct panfrost_perfcnt {
|
||||
struct panfrost_gem_mapping *mapping;
|
||||
unsigned int counterset;
|
||||
size_t bosize;
|
||||
void *buf;
|
||||
struct panfrost_file_priv *user;
|
||||
struct mutex lock;
|
||||
struct completion dump_comp;
|
||||
u32 state;
|
||||
bool owns_as_ref;
|
||||
};
|
||||
|
||||
static void panfrost_perfcnt_hw_disable(struct panfrost_device *pfdev)
|
||||
{
|
||||
struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
|
||||
|
||||
gpu_write(pfdev, GPU_PERFCNT_CFG,
|
||||
GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF));
|
||||
gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0x0);
|
||||
gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0x0);
|
||||
gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0x0);
|
||||
gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
|
||||
|
||||
if (perfcnt->owns_as_ref) {
|
||||
panfrost_mmu_as_put(pfdev, perfcnt->mapping->mmu);
|
||||
perfcnt->owns_as_ref = false;
|
||||
}
|
||||
}
|
||||
|
||||
void panfrost_perfcnt_clean_cache_done(struct panfrost_device *pfdev)
|
||||
{
|
||||
complete(&pfdev->perfcnt->dump_comp);
|
||||
|
|
@ -42,30 +64,136 @@ void panfrost_perfcnt_clean_cache_done(struct panfrost_device *pfdev)
|
|||
|
||||
void panfrost_perfcnt_sample_done(struct panfrost_device *pfdev)
|
||||
{
|
||||
gpu_write(pfdev, GPU_CMD, GPU_CMD_CLEAN_CACHES);
|
||||
if (pfdev->features.selected_coherency != COHERENCY_ACE)
|
||||
gpu_write(pfdev, GPU_CMD, GPU_CMD_CLEAN_CACHES);
|
||||
else
|
||||
complete(&pfdev->perfcnt->dump_comp);
|
||||
}
|
||||
|
||||
static int panfrost_perfcnt_dump_locked(struct panfrost_device *pfdev)
|
||||
static int panfrost_perfcnt_hw_enable(struct panfrost_device *pfdev)
|
||||
{
|
||||
u64 gpuva;
|
||||
struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
|
||||
u32 cfg, as;
|
||||
int ret;
|
||||
|
||||
reinit_completion(&pfdev->perfcnt->dump_comp);
|
||||
gpuva = pfdev->perfcnt->mapping->mmnode.start << PAGE_SHIFT;
|
||||
gpu_write(pfdev, GPU_PERFCNT_BASE_LO, lower_32_bits(gpuva));
|
||||
gpu_write(pfdev, GPU_PERFCNT_BASE_HI, upper_32_bits(gpuva));
|
||||
gpu_write(pfdev, GPU_INT_CLEAR,
|
||||
GPU_IRQ_CLEAN_CACHES_COMPLETED |
|
||||
GPU_IRQ_PERFCNT_SAMPLE_COMPLETED);
|
||||
gpu_write(pfdev, GPU_CMD, GPU_CMD_PERFCNT_SAMPLE);
|
||||
lockdep_assert_held(&pfdev->reset.lock);
|
||||
drm_WARN_ON(&pfdev->base, perfcnt->owns_as_ref);
|
||||
|
||||
ret = panfrost_mmu_as_get(pfdev, perfcnt->mapping->mmu);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
perfcnt->owns_as_ref = true;
|
||||
|
||||
as = ret;
|
||||
cfg = GPU_PERFCNT_CFG_AS(as) |
|
||||
GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_MANUAL);
|
||||
|
||||
/*
|
||||
* Bifrost GPUs have 2 set of counters, but we're only interested by
|
||||
* the first one for now.
|
||||
*/
|
||||
if (panfrost_model_is_bifrost(pfdev))
|
||||
cfg |= GPU_PERFCNT_CFG_SETSEL(perfcnt->counterset);
|
||||
|
||||
gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0xffffffff);
|
||||
gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0xffffffff);
|
||||
gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0xffffffff);
|
||||
|
||||
/*
|
||||
* Due to PRLAM-8186 we need to disable the Tiler before we enable HW
|
||||
* counters.
|
||||
*/
|
||||
if (panfrost_has_hw_issue(pfdev, HW_ISSUE_8186))
|
||||
gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
|
||||
else
|
||||
gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0xffffffff);
|
||||
|
||||
gpu_write(pfdev, GPU_PERFCNT_CFG, cfg);
|
||||
|
||||
if (panfrost_has_hw_issue(pfdev, HW_ISSUE_8186))
|
||||
gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0xffffffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int panfrost_perfcnt_dump_locked(struct panfrost_device *pfdev, u32 *state)
|
||||
{
|
||||
struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
|
||||
u64 gpuva = perfcnt->mapping->mmnode.start << PAGE_SHIFT;
|
||||
int ret;
|
||||
|
||||
scoped_guard(rwsem_read, &pfdev->reset.lock) {
|
||||
*state = perfcnt->state;
|
||||
if (perfcnt->state & PANFROST_PERFCNT_SESSION_DEAD)
|
||||
return -EIO;
|
||||
|
||||
perfcnt->state = 0;
|
||||
|
||||
reinit_completion(&pfdev->perfcnt->dump_comp);
|
||||
|
||||
gpu_write(pfdev, GPU_PERFCNT_BASE_LO, lower_32_bits(gpuva));
|
||||
gpu_write(pfdev, GPU_PERFCNT_BASE_HI, upper_32_bits(gpuva));
|
||||
gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_CLEAN_CACHES_COMPLETED |
|
||||
GPU_IRQ_PERFCNT_SAMPLE_COMPLETED);
|
||||
gpu_write(pfdev, GPU_CMD, GPU_CMD_PERFCNT_SAMPLE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we release the reset semaphore because perfcnt should not get in the way
|
||||
* of a HW reset. Besides, a legitimate reset might be issued during the wait.
|
||||
*/
|
||||
ret = wait_for_completion_interruptible_timeout(&pfdev->perfcnt->dump_comp,
|
||||
msecs_to_jiffies(1000));
|
||||
|
||||
if (!ret)
|
||||
ret = -ETIMEDOUT;
|
||||
else if (ret > 0)
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
/* We need to restore perfcnt state so the next successful dump can relay it to UM */
|
||||
if (ret < 0) {
|
||||
perfcnt->state |= *state;
|
||||
*state = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
scoped_guard(rwsem_read, &pfdev->reset.lock) {
|
||||
*state |= perfcnt->state;
|
||||
|
||||
/* UM must re-enable their session before requesting new dumps. */
|
||||
if (perfcnt->state & PANFROST_PERFCNT_SESSION_DEAD)
|
||||
return -EIO;
|
||||
|
||||
/* If we faced a reset during our SAMPLE, the user needs to try again. */
|
||||
if (perfcnt->state & PANFROST_PERFCNT_SESSION_INTERRUPTED_BY_RESET)
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int panfrost_perfcnt_disable_locked(struct panfrost_device *pfdev,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct panfrost_file_priv *user = file_priv->driver_priv;
|
||||
struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
|
||||
struct iosys_map map = IOSYS_MAP_INIT_VADDR(perfcnt->buf);
|
||||
|
||||
if (user != perfcnt->user)
|
||||
return -EINVAL;
|
||||
|
||||
scoped_guard(rwsem_read, &pfdev->reset.lock) {
|
||||
panfrost_perfcnt_hw_disable(pfdev);
|
||||
perfcnt->user = NULL;
|
||||
}
|
||||
|
||||
drm_gem_vunmap(&perfcnt->mapping->obj->base.base, &map);
|
||||
perfcnt->buf = NULL;
|
||||
panfrost_gem_close(&perfcnt->mapping->obj->base.base, file_priv);
|
||||
panfrost_gem_mapping_put(perfcnt->mapping);
|
||||
perfcnt->mapping = NULL;
|
||||
pm_runtime_put_autosuspend(pfdev->base.dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
|
||||
|
|
@ -74,14 +202,29 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
|
|||
{
|
||||
struct panfrost_file_priv *user = file_priv->driver_priv;
|
||||
struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
|
||||
struct iosys_map map;
|
||||
struct drm_gem_shmem_object *bo;
|
||||
u32 cfg, as;
|
||||
struct iosys_map map;
|
||||
int ret;
|
||||
|
||||
if (user == perfcnt->user)
|
||||
if (perfcnt->user == user) {
|
||||
scoped_guard(rwsem_read, &pfdev->reset.lock) {
|
||||
if (perfcnt->state & PANFROST_PERFCNT_SESSION_DEAD) {
|
||||
/* A successful reset might've come through in the time gap
|
||||
* between the last failed one and this re-enable attempt.
|
||||
*/
|
||||
ret = (perfcnt->owns_as_ref) ? 0 :
|
||||
panfrost_perfcnt_hw_enable(pfdev);
|
||||
if (!ret)
|
||||
perfcnt->state = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
else if (perfcnt->user)
|
||||
}
|
||||
|
||||
if (perfcnt->user)
|
||||
return -EBUSY;
|
||||
|
||||
ret = pm_runtime_get_sync(pfdev->base.dev);
|
||||
|
|
@ -109,65 +252,30 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
|
|||
ret = drm_gem_vmap(&bo->base, &map);
|
||||
if (ret)
|
||||
goto err_put_mapping;
|
||||
|
||||
perfcnt->buf = map.vaddr;
|
||||
perfcnt->counterset = counterset;
|
||||
|
||||
panfrost_gem_internal_set_label(&bo->base, "Perfcnt sample buffer");
|
||||
|
||||
/*
|
||||
* Invalidate the cache and clear the counters to start from a fresh
|
||||
* state.
|
||||
*/
|
||||
reinit_completion(&pfdev->perfcnt->dump_comp);
|
||||
gpu_write(pfdev, GPU_INT_CLEAR,
|
||||
GPU_IRQ_CLEAN_CACHES_COMPLETED |
|
||||
GPU_IRQ_PERFCNT_SAMPLE_COMPLETED);
|
||||
gpu_write(pfdev, GPU_CMD, GPU_CMD_PERFCNT_CLEAR);
|
||||
gpu_write(pfdev, GPU_CMD, GPU_CMD_CLEAN_INV_CACHES);
|
||||
ret = wait_for_completion_timeout(&pfdev->perfcnt->dump_comp,
|
||||
msecs_to_jiffies(1000));
|
||||
if (!ret) {
|
||||
ret = -ETIMEDOUT;
|
||||
goto err_vunmap;
|
||||
scoped_guard(rwsem_read, &pfdev->reset.lock) {
|
||||
/*
|
||||
* Clear the counters to start from a fresh state.
|
||||
*/
|
||||
gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_PERFCNT_SAMPLE_COMPLETED);
|
||||
gpu_write(pfdev, GPU_CMD, GPU_CMD_PERFCNT_CLEAR);
|
||||
|
||||
ret = panfrost_perfcnt_hw_enable(pfdev);
|
||||
if (ret)
|
||||
goto err_vunmap;
|
||||
|
||||
perfcnt->user = user;
|
||||
perfcnt->state = 0;
|
||||
}
|
||||
|
||||
ret = panfrost_mmu_as_get(pfdev, perfcnt->mapping->mmu);
|
||||
if (ret < 0)
|
||||
goto err_vunmap;
|
||||
|
||||
as = ret;
|
||||
cfg = GPU_PERFCNT_CFG_AS(as) |
|
||||
GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_MANUAL);
|
||||
|
||||
/*
|
||||
* Bifrost GPUs have 2 set of counters, but we're only interested by
|
||||
* the first one for now.
|
||||
*/
|
||||
if (panfrost_model_is_bifrost(pfdev))
|
||||
cfg |= GPU_PERFCNT_CFG_SETSEL(counterset);
|
||||
|
||||
gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0xffffffff);
|
||||
gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0xffffffff);
|
||||
gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0xffffffff);
|
||||
|
||||
/*
|
||||
* Due to PRLAM-8186 we need to disable the Tiler before we enable HW
|
||||
* counters.
|
||||
*/
|
||||
if (panfrost_has_hw_issue(pfdev, HW_ISSUE_8186))
|
||||
gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
|
||||
else
|
||||
gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0xffffffff);
|
||||
|
||||
gpu_write(pfdev, GPU_PERFCNT_CFG, cfg);
|
||||
|
||||
if (panfrost_has_hw_issue(pfdev, HW_ISSUE_8186))
|
||||
gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0xffffffff);
|
||||
|
||||
/* The BO ref is retained by the mapping. */
|
||||
drm_gem_object_put(&bo->base);
|
||||
|
||||
perfcnt->user = user;
|
||||
|
||||
return 0;
|
||||
|
||||
err_vunmap:
|
||||
|
|
@ -183,35 +291,6 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int panfrost_perfcnt_disable_locked(struct panfrost_device *pfdev,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct panfrost_file_priv *user = file_priv->driver_priv;
|
||||
struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
|
||||
struct iosys_map map = IOSYS_MAP_INIT_VADDR(perfcnt->buf);
|
||||
|
||||
if (user != perfcnt->user)
|
||||
return -EINVAL;
|
||||
|
||||
gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0x0);
|
||||
gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0x0);
|
||||
gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0x0);
|
||||
gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
|
||||
gpu_write(pfdev, GPU_PERFCNT_CFG,
|
||||
GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF));
|
||||
|
||||
perfcnt->user = NULL;
|
||||
drm_gem_vunmap(&perfcnt->mapping->obj->base.base, &map);
|
||||
perfcnt->buf = NULL;
|
||||
panfrost_gem_close(&perfcnt->mapping->obj->base.base, file_priv);
|
||||
panfrost_mmu_as_put(pfdev, perfcnt->mapping->mmu);
|
||||
panfrost_gem_mapping_put(perfcnt->mapping);
|
||||
perfcnt->mapping = NULL;
|
||||
pm_runtime_put_autosuspend(pfdev->base.dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int panfrost_ioctl_perfcnt_enable(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
|
|
@ -252,13 +331,16 @@ int panfrost_ioctl_perfcnt_dump(struct drm_device *dev, void *data,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (req->pad)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&perfcnt->lock);
|
||||
if (perfcnt->user != file_priv->driver_priv) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = panfrost_perfcnt_dump_locked(pfdev);
|
||||
ret = panfrost_perfcnt_dump_locked(pfdev, &req->state);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
|
|
@ -325,18 +407,12 @@ int panfrost_perfcnt_init(struct panfrost_device *pfdev)
|
|||
return -ENOMEM;
|
||||
|
||||
perfcnt->bosize = size;
|
||||
pfdev->perfcnt = perfcnt;
|
||||
mutex_init(&perfcnt->lock);
|
||||
init_completion(&perfcnt->dump_comp);
|
||||
|
||||
/* Start with everything disabled. */
|
||||
gpu_write(pfdev, GPU_PERFCNT_CFG,
|
||||
GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF));
|
||||
gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0);
|
||||
gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0);
|
||||
gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0);
|
||||
gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
|
||||
|
||||
init_completion(&perfcnt->dump_comp);
|
||||
mutex_init(&perfcnt->lock);
|
||||
pfdev->perfcnt = perfcnt;
|
||||
panfrost_perfcnt_hw_disable(pfdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -344,10 +420,27 @@ int panfrost_perfcnt_init(struct panfrost_device *pfdev)
|
|||
void panfrost_perfcnt_fini(struct panfrost_device *pfdev)
|
||||
{
|
||||
/* Disable everything before leaving. */
|
||||
gpu_write(pfdev, GPU_PERFCNT_CFG,
|
||||
GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF));
|
||||
gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0);
|
||||
gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0);
|
||||
gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0);
|
||||
gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
|
||||
panfrost_perfcnt_hw_disable(pfdev);
|
||||
}
|
||||
|
||||
void panfrost_perfcnt_reset(struct panfrost_device *pfdev)
|
||||
{
|
||||
struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
|
||||
|
||||
if (drm_WARN_ON(&pfdev->base, !perfcnt))
|
||||
return;
|
||||
|
||||
lockdep_assert_held(&pfdev->reset.lock);
|
||||
|
||||
if (!perfcnt->user)
|
||||
return;
|
||||
|
||||
/* All active AS are released during the MMU post_reset. */
|
||||
perfcnt->owns_as_ref = false;
|
||||
perfcnt->state |= PANFROST_PERFCNT_SESSION_INTERRUPTED_BY_RESET;
|
||||
if (panfrost_perfcnt_hw_enable(pfdev))
|
||||
perfcnt->state |= PANFROST_PERFCNT_SESSION_DEAD;
|
||||
|
||||
/* Unblock pending sample requests. */
|
||||
complete(&perfcnt->dump_comp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,5 +14,6 @@ int panfrost_ioctl_perfcnt_enable(struct drm_device *dev, void *data,
|
|||
struct drm_file *file_priv);
|
||||
int panfrost_ioctl_perfcnt_dump(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
void panfrost_perfcnt_reset(struct panfrost_device *pfdev);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1081,7 +1081,7 @@ static int panthor_ioctl_bo_mmap_offset(struct drm_device *ddev, void *data,
|
|||
struct drm_panthor_bo_mmap_offset *args = data;
|
||||
struct panthor_gem_object *bo;
|
||||
struct drm_gem_object *obj;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
if (args->pad)
|
||||
return -EINVAL;
|
||||
|
|
@ -1096,10 +1096,6 @@ static int panthor_ioctl_bo_mmap_offset(struct drm_device *ddev, void *data,
|
|||
goto out;
|
||||
}
|
||||
|
||||
ret = drm_gem_create_mmap_offset(obj);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
args->offset = drm_vma_node_offset_addr(&obj->vma_node);
|
||||
|
||||
out:
|
||||
|
|
|
|||
|
|
@ -744,6 +744,9 @@ static int panthor_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct *v
|
|||
struct panthor_gem_object *bo = to_panthor_bo(obj);
|
||||
int ret;
|
||||
|
||||
if (bo->flags & DRM_PANTHOR_BO_NO_MMAP)
|
||||
return -EINVAL;
|
||||
|
||||
if (drm_gem_is_imported(obj)) {
|
||||
/* Reset both vm_ops and vm_private_data, so we don't end up with
|
||||
* vm_ops pointing to our implementation if the dma-buf backend
|
||||
|
|
|
|||
|
|
@ -3770,12 +3770,18 @@ int panthor_group_destroy(struct panthor_file *pfile, u32 group_handle)
|
|||
struct panthor_group_pool *gpool = pfile->groups;
|
||||
struct panthor_device *ptdev = pfile->ptdev;
|
||||
struct panthor_scheduler *sched = ptdev->scheduler;
|
||||
struct panthor_group *group;
|
||||
struct panthor_group *group = NULL;
|
||||
|
||||
if (!xa_get_mark(&gpool->xa, group_handle, GROUP_REGISTERED))
|
||||
return -EINVAL;
|
||||
/*
|
||||
* Check the mark and erase the entry atomically, so a concurrent
|
||||
* destroy + create can't make us erase a group that's still being
|
||||
* initialized and happens to reuse the same handle.
|
||||
*/
|
||||
xa_lock(&gpool->xa);
|
||||
if (xa_get_mark(&gpool->xa, group_handle, GROUP_REGISTERED))
|
||||
group = __xa_erase(&gpool->xa, group_handle);
|
||||
xa_unlock(&gpool->xa);
|
||||
|
||||
group = xa_erase(&gpool->xa, group_handle);
|
||||
if (!group)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@
|
|||
#include <drm/drm_bridge_connector.h>
|
||||
#include <drm/drm_managed.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
||||
#include "rockchip_drm_drv.h"
|
||||
|
||||
|
|
@ -34,6 +33,7 @@
|
|||
|
||||
#define RK3576_IOC_HDMI_HPD_STATUS 0xa440
|
||||
#define RK3576_HDMI_LEVEL_INT BIT(3)
|
||||
#define RK3576_HDMI_OHPD_INT BIT(4)
|
||||
|
||||
#define RK3576_VO0_GRF_SOC_CON1 0x0004
|
||||
#define RK3576_HDMI_FRL_MOD BIT(0)
|
||||
|
|
@ -64,7 +64,9 @@
|
|||
#define RK3588_HPD_HDMI1_IO_EN_MASK BIT(13)
|
||||
#define RK3588_GRF_SOC_STATUS1 0x0384
|
||||
#define RK3588_HDMI0_LEVEL_INT BIT(16)
|
||||
#define RK3588_HDMI0_OHPD_INT BIT(17)
|
||||
#define RK3588_HDMI1_LEVEL_INT BIT(24)
|
||||
#define RK3588_HDMI1_OHPD_INT BIT(25)
|
||||
#define RK3588_GRF_VO1_CON3 0x000c
|
||||
#define RK3588_GRF_VO1_CON6 0x0018
|
||||
#define RK3588_COLOR_DEPTH_MASK GENMASK(7, 4)
|
||||
|
|
@ -96,6 +98,7 @@ struct rockchip_hdmi_qp {
|
|||
struct phy *phy;
|
||||
struct gpio_desc *frl_enable_gpio;
|
||||
struct delayed_work hpd_work;
|
||||
int hpd_irq;
|
||||
int port_id;
|
||||
const struct rockchip_hdmi_qp_ctrl_ops *ctrl_ops;
|
||||
unsigned long long tmds_char_rate;
|
||||
|
|
@ -274,9 +277,8 @@ dw_hdmi_qp_rk3588_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
|
|||
return val ? connector_status_connected : connector_status_disconnected;
|
||||
}
|
||||
|
||||
static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
|
||||
static void dw_hdmi_qp_rk3588_unmask_hpd(struct rockchip_hdmi_qp *hdmi)
|
||||
{
|
||||
struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
|
||||
u32 val;
|
||||
|
||||
if (hdmi->port_id)
|
||||
|
|
@ -289,11 +291,48 @@ static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
|
|||
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
|
||||
}
|
||||
|
||||
static void dw_hdmi_qp_rk3588_mask_hpd(struct rockchip_hdmi_qp *hdmi)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (hdmi->port_id)
|
||||
val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
|
||||
else
|
||||
val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
|
||||
|
||||
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
|
||||
}
|
||||
|
||||
static void dw_hdmi_qp_rk3588_enable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
|
||||
{
|
||||
struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
|
||||
|
||||
dw_hdmi_qp_rk3588_unmask_hpd(hdmi);
|
||||
enable_irq(hdmi->hpd_irq);
|
||||
}
|
||||
|
||||
static void dw_hdmi_qp_rk3588_disable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
|
||||
{
|
||||
struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
|
||||
|
||||
disable_irq(hdmi->hpd_irq);
|
||||
dw_hdmi_qp_rk3588_mask_hpd(hdmi);
|
||||
|
||||
/*
|
||||
* Cannot use the _sync() variant: the work takes mode_config.mutex,
|
||||
* which the connector probe path already holds when acquiring the
|
||||
* hpd_state_mutex this caller runs under. Requeuing is already ruled
|
||||
* out by disable_irq().
|
||||
*/
|
||||
cancel_delayed_work(&hdmi->hpd_work);
|
||||
}
|
||||
|
||||
static const struct dw_hdmi_qp_phy_ops rk3588_hdmi_phy_ops = {
|
||||
.init = dw_hdmi_qp_rk3588_phy_init,
|
||||
.disable = dw_hdmi_qp_rk3588_phy_disable,
|
||||
.read_hpd = dw_hdmi_qp_rk3588_read_hpd,
|
||||
.setup_hpd = dw_hdmi_qp_rk3588_setup_hpd,
|
||||
.enable_hpd = dw_hdmi_qp_rk3588_enable_hpd,
|
||||
.disable_hpd = dw_hdmi_qp_rk3588_disable_hpd,
|
||||
};
|
||||
|
||||
static enum drm_connector_status
|
||||
|
|
@ -308,23 +347,49 @@ dw_hdmi_qp_rk3576_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
|
|||
connector_status_connected : connector_status_disconnected;
|
||||
}
|
||||
|
||||
static void dw_hdmi_qp_rk3576_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
|
||||
static void dw_hdmi_qp_rk3576_unmask_hpd(struct rockchip_hdmi_qp *hdmi)
|
||||
{
|
||||
regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0,
|
||||
FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1) |
|
||||
FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0));
|
||||
}
|
||||
|
||||
static void dw_hdmi_qp_rk3576_mask_hpd(struct rockchip_hdmi_qp *hdmi)
|
||||
{
|
||||
regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0,
|
||||
FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1));
|
||||
}
|
||||
|
||||
static void dw_hdmi_qp_rk3576_enable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
|
||||
{
|
||||
struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
|
||||
u32 val;
|
||||
|
||||
val = (FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1) |
|
||||
FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0));
|
||||
dw_hdmi_qp_rk3576_unmask_hpd(hdmi);
|
||||
enable_irq(hdmi->hpd_irq);
|
||||
}
|
||||
|
||||
regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
|
||||
regmap_write(hdmi->regmap, 0xa404, 0xffff0102);
|
||||
static void dw_hdmi_qp_rk3576_disable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
|
||||
{
|
||||
struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
|
||||
|
||||
disable_irq(hdmi->hpd_irq);
|
||||
dw_hdmi_qp_rk3576_mask_hpd(hdmi);
|
||||
|
||||
/*
|
||||
* Cannot use the _sync() variant: the work takes mode_config.mutex,
|
||||
* which the connector probe path already holds when acquiring the
|
||||
* hpd_state_mutex this caller runs under. Requeuing is already ruled
|
||||
* out by disable_irq().
|
||||
*/
|
||||
cancel_delayed_work(&hdmi->hpd_work);
|
||||
}
|
||||
|
||||
static const struct dw_hdmi_qp_phy_ops rk3576_hdmi_phy_ops = {
|
||||
.init = dw_hdmi_qp_rk3588_phy_init,
|
||||
.disable = dw_hdmi_qp_rk3588_phy_disable,
|
||||
.read_hpd = dw_hdmi_qp_rk3576_read_hpd,
|
||||
.setup_hpd = dw_hdmi_qp_rk3576_setup_hpd,
|
||||
.enable_hpd = dw_hdmi_qp_rk3576_enable_hpd,
|
||||
.disable_hpd = dw_hdmi_qp_rk3576_disable_hpd,
|
||||
};
|
||||
|
||||
static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work)
|
||||
|
|
@ -332,26 +397,19 @@ static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work)
|
|||
struct rockchip_hdmi_qp *hdmi = container_of(work,
|
||||
struct rockchip_hdmi_qp,
|
||||
hpd_work.work);
|
||||
struct drm_device *drm = hdmi->encoder.encoder.dev;
|
||||
bool changed;
|
||||
|
||||
if (drm) {
|
||||
changed = drm_helper_hpd_irq_event(drm);
|
||||
if (changed)
|
||||
dev_dbg(hdmi->dev, "connector status changed\n");
|
||||
}
|
||||
dw_hdmi_qp_hpd_notify(hdmi->hdmi);
|
||||
}
|
||||
|
||||
static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
|
||||
{
|
||||
struct rockchip_hdmi_qp *hdmi = dev_id;
|
||||
u32 intr_stat, val;
|
||||
u32 intr_stat;
|
||||
|
||||
regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &intr_stat);
|
||||
if (intr_stat) {
|
||||
val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
|
||||
|
||||
regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
|
||||
if (intr_stat & RK3576_HDMI_OHPD_INT) {
|
||||
dw_hdmi_qp_rk3576_mask_hpd(hdmi);
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
|
|
@ -361,15 +419,11 @@ static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
|
|||
static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct rockchip_hdmi_qp *hdmi = dev_id;
|
||||
u32 val;
|
||||
|
||||
val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1);
|
||||
regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
|
||||
mod_delayed_work(system_percpu_wq, &hdmi->hpd_work,
|
||||
msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
|
||||
|
||||
val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0);
|
||||
regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
|
||||
dw_hdmi_qp_rk3576_unmask_hpd(hdmi);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
|
@ -377,16 +431,14 @@ static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id)
|
|||
static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
|
||||
{
|
||||
struct rockchip_hdmi_qp *hdmi = dev_id;
|
||||
u32 intr_stat, val;
|
||||
u32 intr_stat;
|
||||
|
||||
regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
|
||||
|
||||
intr_stat &= hdmi->port_id ? RK3588_HDMI1_OHPD_INT : RK3588_HDMI0_OHPD_INT;
|
||||
|
||||
if (intr_stat) {
|
||||
if (hdmi->port_id)
|
||||
val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
|
||||
else
|
||||
val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
|
||||
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
|
||||
dw_hdmi_qp_rk3588_mask_hpd(hdmi);
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
|
|
@ -396,22 +448,11 @@ static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
|
|||
static irqreturn_t dw_hdmi_qp_rk3588_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct rockchip_hdmi_qp *hdmi = dev_id;
|
||||
u32 val;
|
||||
|
||||
if (hdmi->port_id)
|
||||
val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_CLR, 1);
|
||||
else
|
||||
val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_CLR, 1);
|
||||
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
|
||||
|
||||
mod_delayed_work(system_percpu_wq, &hdmi->hpd_work,
|
||||
msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
|
||||
|
||||
if (hdmi->port_id)
|
||||
val |= FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 0);
|
||||
else
|
||||
val |= FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 0);
|
||||
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
|
||||
dw_hdmi_qp_rk3588_unmask_hpd(hdmi);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
|
@ -424,11 +465,11 @@ static void dw_hdmi_qp_rk3576_io_init(struct rockchip_hdmi_qp *hdmi)
|
|||
FIELD_PREP_WM16(RK3576_SDAIN_MASK, 1) |
|
||||
FIELD_PREP_WM16(RK3576_HDMI_GRANT_SEL, 1) |
|
||||
FIELD_PREP_WM16(RK3576_I2S_SEL_MASK, 1);
|
||||
|
||||
regmap_write(hdmi->vo_regmap, RK3576_VO0_GRF_SOC_CON14, val);
|
||||
|
||||
val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0);
|
||||
regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
|
||||
regmap_write(hdmi->regmap, 0xa404, 0xffff0102);
|
||||
|
||||
dw_hdmi_qp_rk3576_mask_hpd(hdmi);
|
||||
}
|
||||
|
||||
static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
|
||||
|
|
@ -453,11 +494,7 @@ static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
|
|||
val = FIELD_PREP_WM16(RK3588_HDMI0_GRANT_SEL, 1);
|
||||
regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val);
|
||||
|
||||
if (hdmi->port_id)
|
||||
val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
|
||||
else
|
||||
val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
|
||||
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
|
||||
dw_hdmi_qp_rk3588_mask_hpd(hdmi);
|
||||
}
|
||||
|
||||
static void dw_hdmi_qp_rk3576_enc_init(struct rockchip_hdmi_qp *hdmi,
|
||||
|
|
@ -561,9 +598,9 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
|
|||
struct resource *res;
|
||||
struct clk_bulk_data *clks;
|
||||
struct clk *ref_clk;
|
||||
int ret, irq, i;
|
||||
int ret, i;
|
||||
|
||||
if (!pdev->dev.of_node)
|
||||
if (!dev->of_node)
|
||||
return -ENODEV;
|
||||
|
||||
hdmi = drmm_kzalloc(drm, sizeof(*hdmi), GFP_KERNEL);
|
||||
|
|
@ -583,7 +620,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
|
|||
return dev_err_probe(dev, -ENODEV, "Missing platform ctrl ops\n");
|
||||
|
||||
hdmi->ctrl_ops = cfg->ctrl_ops;
|
||||
hdmi->dev = &pdev->dev;
|
||||
hdmi->dev = dev;
|
||||
hdmi->port_id = -ENODEV;
|
||||
|
||||
/* Identify port ID by matching base IO address */
|
||||
|
|
@ -594,7 +631,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
|
|||
}
|
||||
}
|
||||
if (hdmi->port_id < 0)
|
||||
return dev_err_probe(hdmi->dev, hdmi->port_id,
|
||||
return dev_err_probe(dev, hdmi->port_id,
|
||||
"Failed to match HDMI port ID\n");
|
||||
|
||||
plat_data.phy_ops = cfg->phy_ops;
|
||||
|
|
@ -622,37 +659,36 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
|
|||
hdmi->regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||
"rockchip,grf");
|
||||
if (IS_ERR(hdmi->regmap))
|
||||
return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->regmap),
|
||||
return dev_err_probe(dev, PTR_ERR(hdmi->regmap),
|
||||
"Unable to get rockchip,grf\n");
|
||||
|
||||
hdmi->vo_regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||
"rockchip,vo-grf");
|
||||
if (IS_ERR(hdmi->vo_regmap))
|
||||
return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->vo_regmap),
|
||||
return dev_err_probe(dev, PTR_ERR(hdmi->vo_regmap),
|
||||
"Unable to get rockchip,vo-grf\n");
|
||||
|
||||
ret = devm_clk_bulk_get_all_enabled(hdmi->dev, &clks);
|
||||
ret = devm_clk_bulk_get_all_enabled(dev, &clks);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(hdmi->dev, ret, "Failed to get clocks\n");
|
||||
return dev_err_probe(dev, ret, "Failed to get clocks\n");
|
||||
|
||||
ref_clk = clk_get(hdmi->dev, "ref");
|
||||
ref_clk = clk_get(dev, "ref");
|
||||
if (IS_ERR(ref_clk))
|
||||
return dev_err_probe(hdmi->dev, PTR_ERR(ref_clk),
|
||||
return dev_err_probe(dev, PTR_ERR(ref_clk),
|
||||
"Failed to get ref clock\n");
|
||||
|
||||
plat_data.ref_clk_rate = clk_get_rate(ref_clk);
|
||||
clk_put(ref_clk);
|
||||
|
||||
hdmi->frl_enable_gpio = devm_gpiod_get_optional(hdmi->dev, "frl-enable",
|
||||
hdmi->frl_enable_gpio = devm_gpiod_get_optional(dev, "frl-enable",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(hdmi->frl_enable_gpio))
|
||||
return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->frl_enable_gpio),
|
||||
return dev_err_probe(dev, PTR_ERR(hdmi->frl_enable_gpio),
|
||||
"Failed to request FRL enable GPIO\n");
|
||||
|
||||
hdmi->phy = devm_of_phy_get_by_index(dev, dev->of_node, 0);
|
||||
if (IS_ERR(hdmi->phy))
|
||||
return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->phy),
|
||||
"Failed to get phy\n");
|
||||
return dev_err_probe(dev, PTR_ERR(hdmi->phy), "Failed to get phy\n");
|
||||
|
||||
cfg->ctrl_ops->io_init(hdmi);
|
||||
|
||||
|
|
@ -666,14 +702,14 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
|
|||
if (plat_data.cec_irq < 0)
|
||||
return plat_data.cec_irq;
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "hpd");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
hdmi->hpd_irq = platform_get_irq_byname(pdev, "hpd");
|
||||
if (hdmi->hpd_irq < 0)
|
||||
return hdmi->hpd_irq;
|
||||
|
||||
ret = devm_request_threaded_irq(hdmi->dev, irq,
|
||||
ret = devm_request_threaded_irq(dev, hdmi->hpd_irq,
|
||||
cfg->ctrl_ops->hardirq_callback,
|
||||
cfg->ctrl_ops->irq_callback,
|
||||
IRQF_SHARED, "dw-hdmi-qp-hpd",
|
||||
IRQF_NO_AUTOEN, "dw-hdmi-qp-hpd",
|
||||
hdmi);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -681,20 +717,20 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
|
|||
drm_encoder_helper_add(encoder, &dw_hdmi_qp_rockchip_encoder_helper_funcs);
|
||||
ret = drmm_encoder_init(drm, encoder, NULL, DRM_MODE_ENCODER_TMDS, NULL);
|
||||
if (ret)
|
||||
return dev_err_probe(hdmi->dev, ret, "Failed to init encoder");
|
||||
|
||||
platform_set_drvdata(pdev, hdmi);
|
||||
return dev_err_probe(dev, ret, "Failed to init encoder\n");
|
||||
|
||||
hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data);
|
||||
if (IS_ERR(hdmi->hdmi))
|
||||
return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->hdmi),
|
||||
"Failed to bind dw-hdmi-qp");
|
||||
return dev_err_probe(dev, PTR_ERR(hdmi->hdmi),
|
||||
"Failed to bind dw-hdmi-qp\n");
|
||||
|
||||
connector = drm_bridge_connector_init(drm, encoder);
|
||||
if (IS_ERR(connector))
|
||||
return dev_err_probe(hdmi->dev, PTR_ERR(connector),
|
||||
return dev_err_probe(dev, PTR_ERR(connector),
|
||||
"Failed to init bridge connector\n");
|
||||
|
||||
platform_set_drvdata(pdev, hdmi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -704,6 +740,8 @@ static void dw_hdmi_qp_rockchip_unbind(struct device *dev,
|
|||
{
|
||||
struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
|
||||
|
||||
dev_set_drvdata(dev, NULL);
|
||||
|
||||
cancel_delayed_work_sync(&hdmi->hpd_work);
|
||||
}
|
||||
|
||||
|
|
@ -726,6 +764,11 @@ static int __maybe_unused dw_hdmi_qp_rockchip_suspend(struct device *dev)
|
|||
{
|
||||
struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
|
||||
|
||||
if (!hdmi)
|
||||
return 0;
|
||||
|
||||
cancel_delayed_work_sync(&hdmi->hpd_work);
|
||||
|
||||
dw_hdmi_qp_suspend(dev, hdmi->hdmi);
|
||||
|
||||
return 0;
|
||||
|
|
@ -735,12 +778,14 @@ static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev)
|
|||
{
|
||||
struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
|
||||
|
||||
if (!hdmi)
|
||||
return 0;
|
||||
|
||||
hdmi->ctrl_ops->io_init(hdmi);
|
||||
|
||||
dw_hdmi_qp_resume(dev, hdmi->hdmi);
|
||||
|
||||
if (hdmi->encoder.encoder.dev)
|
||||
drm_helper_hpd_irq_event(hdmi->encoder.encoder.dev);
|
||||
dw_hdmi_qp_hpd_notify(hdmi->hdmi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <drm/drm_probe_helper.h>
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/hdmi.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
|
@ -703,7 +704,6 @@ rk3066_hdmi_register(struct drm_device *drm, struct rk3066_hdmi *hdmi)
|
|||
DRM_MODE_ENCODER_TMDS, NULL);
|
||||
|
||||
hdmi->bridge.driver_private = hdmi;
|
||||
hdmi->bridge.funcs = &rk3066_hdmi_bridge_funcs;
|
||||
hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT |
|
||||
DRM_BRIDGE_OP_EDID |
|
||||
DRM_BRIDGE_OP_HDMI |
|
||||
|
|
@ -712,6 +712,7 @@ rk3066_hdmi_register(struct drm_device *drm, struct rk3066_hdmi *hdmi)
|
|||
hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
|
||||
hdmi->bridge.vendor = "Rockchip";
|
||||
hdmi->bridge.product = "RK3066 HDMI";
|
||||
hdmi->bridge.supported_hdmi_ver = HDMI_VERSION_1_4;
|
||||
|
||||
hdmi->bridge.ddc = rk3066_hdmi_i2c_adapter(hdmi);
|
||||
if (IS_ERR(hdmi->bridge.ddc))
|
||||
|
|
@ -747,9 +748,10 @@ static int rk3066_hdmi_bind(struct device *dev, struct device *master,
|
|||
int irq;
|
||||
int ret;
|
||||
|
||||
hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
|
||||
if (!hdmi)
|
||||
return -ENOMEM;
|
||||
hdmi = devm_drm_bridge_alloc(dev, struct rk3066_hdmi, bridge,
|
||||
&rk3066_hdmi_bridge_funcs);
|
||||
if (IS_ERR(hdmi))
|
||||
return PTR_ERR(hdmi);
|
||||
|
||||
hdmi->dev = dev;
|
||||
hdmi->drm_dev = drm;
|
||||
|
|
|
|||
|
|
@ -1202,6 +1202,11 @@ static void drm_sched_cancel_remaining_jobs(struct drm_gpu_scheduler *sched)
|
|||
* is implemented, all jobs will be canceled through it and afterwards cleaned
|
||||
* up through &struct drm_sched_backend_ops.free_job. If cancel_job is not
|
||||
* implemented, memory could leak.
|
||||
*
|
||||
* The user must wait one RCU grace period between signaling the last hardware-
|
||||
* fence and calling this function because the timeline name returned by
|
||||
* scheduler fences must stay valid until all readers have exited their RCU read
|
||||
* side critical section.
|
||||
*/
|
||||
void drm_sched_fini(struct drm_gpu_scheduler *sched)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1985,7 +1985,7 @@ static const struct drm_connector_helper_funcs ssd130x_connector_helper_funcs =
|
|||
};
|
||||
|
||||
static const struct drm_connector_funcs ssd130x_connector_funcs = {
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.atomic_create_state = drm_atomic_helper_connector_create_state,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = drm_connector_cleanup,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
|
|
|
|||
|
|
@ -192,10 +192,6 @@ sun4i_hdmi_connector_clock_valid(const struct drm_connector *connector,
|
|||
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
|
||||
return MODE_BAD;
|
||||
|
||||
/* HDMI 1.0 max TMDS character rate */
|
||||
if (clock > HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ)
|
||||
return MODE_CLOCK_HIGH;
|
||||
|
||||
rounded_rate = clk_round_rate(hdmi->tmds_clk, clock);
|
||||
if (rounded_rate > 0 &&
|
||||
max_t(unsigned long, rounded_rate, clock) -
|
||||
|
|
@ -253,6 +249,15 @@ static struct i2c_adapter *sun4i_hdmi_get_ddc(struct device *dev)
|
|||
}
|
||||
|
||||
static const struct drm_connector_hdmi_funcs sun4i_hdmi_hdmi_connector_funcs = {
|
||||
/*
|
||||
* NOTE: Those are likely to be wrong, but I couldn't find
|
||||
* the actual ones in the BSP.
|
||||
*/
|
||||
.vendor = "AW",
|
||||
.product = "HDMI",
|
||||
.supported_hdmi_ver = HDMI_VERSION_1_2,
|
||||
.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
|
||||
.max_bpc = 8,
|
||||
.tmds_char_rate_valid = sun4i_hdmi_connector_clock_valid,
|
||||
.avi = {
|
||||
.clear_infoframe = sun4i_hdmi_clear_avi_infoframe,
|
||||
|
|
@ -654,19 +659,11 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master,
|
|||
|
||||
drm_connector_helper_add(&hdmi->connector,
|
||||
&sun4i_hdmi_connector_helper_funcs);
|
||||
ret = drmm_connector_hdmi_ini2(drm, &hdmi->connector,
|
||||
/*
|
||||
* NOTE: Those are likely to be
|
||||
* wrong, but I couldn't find the
|
||||
* actual ones in the BSP.
|
||||
*/
|
||||
"AW", "HDMI",
|
||||
ret = drmm_connector_hdmi_init(drm, &hdmi->connector,
|
||||
&sun4i_hdmi_connector_funcs,
|
||||
&sun4i_hdmi_hdmi_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_HDMIA,
|
||||
hdmi->ddc_i2c,
|
||||
BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
|
||||
8);
|
||||
hdmi->ddc_i2c);
|
||||
if (ret) {
|
||||
dev_err(dev,
|
||||
"Couldn't initialise the HDMI connector\n");
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ int drm_sysfb_connector_helper_get_modes(struct drm_connector *connector);
|
|||
.get_modes = drm_sysfb_connector_helper_get_modes
|
||||
|
||||
#define DRM_SYSFB_CONNECTOR_FUNCS \
|
||||
.reset = drm_atomic_helper_connector_reset, \
|
||||
.atomic_create_state = drm_atomic_helper_connector_create_state, \
|
||||
.fill_modes = drm_helper_probe_single_connector_modes, \
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, \
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <drm/drm_gem_atomic_helper.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_gem_shmem_helper.h>
|
||||
#include <drm/drm_modeset_helper.h>
|
||||
#include <drm/drm_plane.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
|
@ -589,7 +590,7 @@ static const struct drm_mode_config_funcs appletbdrm_mode_config_funcs = {
|
|||
};
|
||||
|
||||
static const struct drm_connector_funcs appletbdrm_connector_funcs = {
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.atomic_create_state = drm_atomic_helper_connector_create_state,
|
||||
.destroy = drm_connector_cleanup,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
|
|
@ -724,7 +725,7 @@ static int appletbdrm_setup_mode_config(struct appletbdrm_device *adev)
|
|||
ret = drm_connector_attach_encoder(connector, encoder);
|
||||
|
||||
if (ret) {
|
||||
drm_err(drm, "Failed to initialize simple display pipe\n");
|
||||
drm_err(drm, "Failed to attach connector to encoder\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -821,6 +822,48 @@ static void appletbdrm_shutdown(struct usb_interface *intf)
|
|||
drm_atomic_helper_shutdown(&adev->drm);
|
||||
}
|
||||
|
||||
static int appletbdrm_suspend(struct usb_interface *intf, pm_message_t message)
|
||||
{
|
||||
struct appletbdrm_device *adev = usb_get_intfdata(intf);
|
||||
|
||||
return drm_mode_config_helper_suspend(&adev->drm);
|
||||
}
|
||||
|
||||
static int appletbdrm_resume(struct usb_interface *intf)
|
||||
{
|
||||
struct appletbdrm_device *adev = usb_get_intfdata(intf);
|
||||
|
||||
return drm_mode_config_helper_resume(&adev->drm);
|
||||
}
|
||||
|
||||
static int appletbdrm_reset_resume(struct usb_interface *intf)
|
||||
{
|
||||
struct appletbdrm_device *adev = usb_get_intfdata(intf);
|
||||
struct drm_device *drm = &adev->drm;
|
||||
int ret, resume_ret;
|
||||
|
||||
/*
|
||||
* A reset puts the device back into its initial state, where it
|
||||
* expects the same handshake as during probe. Resume the DRM side
|
||||
* even if the handshake fails, so that the state saved on suspend
|
||||
* is released.
|
||||
*/
|
||||
ret = appletbdrm_get_information(adev);
|
||||
if (ret) {
|
||||
drm_err(drm, "Failed to get display information\n");
|
||||
goto resume;
|
||||
}
|
||||
|
||||
ret = appletbdrm_signal_readiness(adev);
|
||||
if (ret)
|
||||
drm_err(drm, "Failed to signal readiness\n");
|
||||
|
||||
resume:
|
||||
resume_ret = drm_mode_config_helper_resume(drm);
|
||||
|
||||
return ret ? ret : resume_ret;
|
||||
}
|
||||
|
||||
static const struct usb_device_id appletbdrm_usb_id_table[] = {
|
||||
{ USB_DEVICE_INTERFACE_CLASS(0x05ac, 0x8302, USB_CLASS_AUDIO_VIDEO) },
|
||||
{}
|
||||
|
|
@ -832,6 +875,9 @@ static struct usb_driver appletbdrm_usb_driver = {
|
|||
.probe = appletbdrm_probe,
|
||||
.disconnect = appletbdrm_disconnect,
|
||||
.shutdown = appletbdrm_shutdown,
|
||||
.suspend = appletbdrm_suspend,
|
||||
.resume = appletbdrm_resume,
|
||||
.reset_resume = appletbdrm_reset_resume,
|
||||
.id_table = appletbdrm_usb_id_table,
|
||||
};
|
||||
module_usb_driver(appletbdrm_usb_driver);
|
||||
|
|
|
|||
|
|
@ -356,6 +356,10 @@ static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Imported sg tables only come with DMA addresses, no pages to map. */
|
||||
if (!ttm->pages)
|
||||
return -EINVAL;
|
||||
|
||||
if (num_pages == 1 && ttm->caching == ttm_cached &&
|
||||
!(man->use_tt && (ttm->page_flags & TTM_TT_FLAG_DECRYPTED))) {
|
||||
/*
|
||||
|
|
@ -419,7 +423,7 @@ EXPORT_SYMBOL(ttm_bo_kmap_try_from_panic);
|
|||
*
|
||||
* Returns
|
||||
* -ENOMEM: Out of memory.
|
||||
* -EINVAL: Invalid range.
|
||||
* -EINVAL: Invalid range or the BO has no pages to map.
|
||||
*/
|
||||
int ttm_bo_kmap(struct ttm_buffer_object *bo,
|
||||
unsigned long start_page, unsigned long num_pages,
|
||||
|
|
@ -493,7 +497,7 @@ EXPORT_SYMBOL(ttm_bo_kunmap);
|
|||
*
|
||||
* Returns
|
||||
* -ENOMEM: Out of memory.
|
||||
* -EINVAL: Invalid range.
|
||||
* -EINVAL: Invalid range or the BO has no pages to map.
|
||||
*/
|
||||
int ttm_bo_vmap(struct ttm_buffer_object *bo, struct iosys_map *map)
|
||||
{
|
||||
|
|
@ -537,6 +541,9 @@ int ttm_bo_vmap(struct ttm_buffer_object *bo, struct iosys_map *map)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!ttm->pages)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* We need to use vmap to get the desired page protection
|
||||
* or to make the buffer object look contiguous.
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ static const struct drm_connector_helper_funcs vc4_dummy_connector_helper_funcs
|
|||
static const struct drm_connector_funcs vc4_dummy_connector_funcs = {
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.atomic_create_state = drm_atomic_helper_connector_create_state,
|
||||
};
|
||||
|
||||
struct vc4_dummy_output *vc4_dummy_output(struct kunit *test,
|
||||
|
|
|
|||
|
|
@ -303,7 +303,8 @@ static void vc4_bo_purge(struct drm_gem_object *obj)
|
|||
|
||||
drm_vma_node_unmap(&obj->vma_node, dev->anon_inode->i_mapping);
|
||||
|
||||
dma_free_wc(dev->dev, obj->size, bo->base.vaddr, bo->base.dma_addr);
|
||||
dma_free_wc(drm_dev_dma_dev(dev), obj->size, bo->base.vaddr,
|
||||
bo->base.dma_addr);
|
||||
bo->base.vaddr = NULL;
|
||||
bo->madv = __VC4_MADV_PURGED;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,10 +24,8 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/component.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
|
|
@ -273,15 +271,6 @@ static void vc4_component_unbind_all(void *ptr)
|
|||
component_unbind_all(vc4->dev, &vc4->base);
|
||||
}
|
||||
|
||||
static const struct of_device_id vc4_dma_range_matches[] = {
|
||||
{ .compatible = "brcm,bcm2711-hvs" },
|
||||
{ .compatible = "brcm,bcm2712-hvs" },
|
||||
{ .compatible = "brcm,bcm2835-hvs" },
|
||||
{ .compatible = "brcm,bcm2835-v3d" },
|
||||
{ .compatible = "brcm,cygnus-v3d" },
|
||||
{}
|
||||
};
|
||||
|
||||
static int vc4_drm_bind(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
|
@ -294,8 +283,6 @@ static int vc4_drm_bind(struct device *dev)
|
|||
enum vc4_gen gen;
|
||||
int ret = 0;
|
||||
|
||||
dev->coherent_dma_mask = DMA_BIT_MASK(32);
|
||||
|
||||
gen = (enum vc4_gen)of_device_get_match_data(dev);
|
||||
|
||||
if (gen > VC4_GEN_4)
|
||||
|
|
@ -303,21 +290,6 @@ static int vc4_drm_bind(struct device *dev)
|
|||
else
|
||||
driver = &vc4_drm_driver;
|
||||
|
||||
if (gen >= VC4_GEN_6_C)
|
||||
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36));
|
||||
else
|
||||
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
|
||||
|
||||
node = of_find_matching_node_and_match(NULL, vc4_dma_range_matches,
|
||||
NULL);
|
||||
if (node) {
|
||||
ret = of_dma_configure(dev, node, true);
|
||||
of_node_put(node);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
vc4 = devm_drm_dev_alloc(dev, driver, struct vc4_dev, base);
|
||||
if (IS_ERR(vc4))
|
||||
return PTR_ERR(vc4);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/component.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
|
|
@ -1662,6 +1663,15 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
|
|||
hvs->regset.nregs = ARRAY_SIZE(vc4_hvs_regs);
|
||||
}
|
||||
|
||||
if (vc4->gen >= VC4_GEN_6_C) {
|
||||
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (drm_dev_dma_dev(drm) == drm->dev)
|
||||
drm_dev_set_dma_dev(drm, dev);
|
||||
|
||||
if (vc4->gen >= VC4_GEN_5) {
|
||||
struct rpi_firmware *firmware;
|
||||
struct device_node *node;
|
||||
|
|
|
|||
|
|
@ -378,7 +378,7 @@ static const struct drm_connector_funcs vc4_txp_connector_funcs = {
|
|||
.detect = vc4_txp_connector_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = drm_connector_cleanup,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.atomic_create_state = drm_atomic_helper_connector_create_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user