Skip to content

Commit 10247ce

Browse files
jannaumarcan
authored andcommitted
drm/apple: Support DCP shutdown and restart
Required to support module unload / reload. This doesn't quite look like it was intended to be used this way but it works out. For now this is handled as developer feature and taint the kernel on DCP resets. Main area of concern is the lack of reset of the DCP co-processor. It only works if it was correctly shutdown. DCP keeps state after shutdown and "reset". The shared memory DVA used for iomfb message passing is retained. It is possible to reset it but DCP does not react in the same way requiring a different init sequence. It's conceiveable that other state is retained as well causing subtle problems. Signed-off-by: Janne Grunau <[email protected]>
1 parent 6a87391 commit 10247ce

File tree

5 files changed

+136
-34
lines changed

5 files changed

+136
-34
lines changed

drivers/gpu/drm/apple/apple_drv.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,8 @@ static int apple_drm_init_dcp(struct device *dev)
406406
int i, ret, num_dcp = 0;
407407

408408
for_each_matching_node(np, apple_dcp_id_tbl) {
409+
struct device_link *link;
410+
409411
if (!of_device_is_available(np)) {
410412
of_node_put(np);
411413
continue;
@@ -415,6 +417,13 @@ static int apple_drm_init_dcp(struct device *dev)
415417
of_node_put(np);
416418
if (!dcp[num_dcp])
417419
continue;
420+
421+
link = device_link_add(dev, &dcp[num_dcp]->dev,
422+
DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_SUPPLIER);
423+
424+
if (IS_ERR(link))
425+
dev_warn(dev, "dcp[%d] device link failed:%d\n",
426+
num_dcp, PTR_ERR(link));
418427

419428
ret = apple_probe_per_dcp(dev, &apple->drm, dcp[num_dcp],
420429
num_dcp);

drivers/gpu/drm/apple/dcp-internal.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <linux/device.h>
99
#include <linux/mutex.h>
1010
#include <linux/platform_device.h>
11+
#include <linux/reset.h>
1112
#include <linux/scatterlist.h>
1213

1314
#include "iomfb.h"
@@ -87,6 +88,7 @@ struct apple_dcp {
8788
struct apple_rtkit *rtk;
8889
struct apple_crtc *crtc;
8990
struct apple_connector *connector;
91+
struct reset_control *reset;
9092

9193
/* firmware version and compatible firmware version */
9294
enum dcp_firmware_version fw_compat;
@@ -110,6 +112,7 @@ struct apple_dcp {
110112

111113
/* DCP shared memory */
112114
void *shmem;
115+
dma_addr_t shmem_iova;
113116

114117
/* Display registers mappable to the DCP */
115118
struct resource *disp_registers[MAX_DISP_REGISTERS];
@@ -146,6 +149,9 @@ struct apple_dcp {
146149
/* Is the DCP awake? */
147150
bool awake;
148151

152+
/* Is the DCP shutting down? */
153+
bool shutdown;
154+
149155
/* Is the DCP in the process of going to sleep? */
150156
bool sleeping;
151157

drivers/gpu/drm/apple/dcp.c

Lines changed: 77 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/module.h>
1515
#include <linux/moduleparam.h>
1616
#include <linux/of_device.h>
17+
#include <linux/platform_device.h>
1718
#include <linux/slab.h>
1819
#include <linux/soc/apple/rtkit.h>
1920
#include <linux/string.h>
@@ -422,7 +423,11 @@ static int dcp_comp_bind(struct device *dev, struct device *main, void *data)
422423
if (IS_ERR(dcp->coproc_reg))
423424
return PTR_ERR(dcp->coproc_reg);
424425

425-
of_platform_default_populate(dev->of_node, NULL, dev);
426+
dcp->reset = devm_reset_control_array_get_exclusive(dev);
427+
if (IS_ERR(dcp->reset)) {
428+
return dev_err_probe(dev, PTR_ERR(dcp->reset),
429+
"Failed to get reset control");
430+
}
426431

427432
if (!show_notch)
428433
ret = of_property_read_u32(dev->of_node, "apple,notch-height",
@@ -509,13 +514,19 @@ static int dcp_comp_bind(struct device *dev, struct device *main, void *data)
509514
return dev_err_probe(dev, PTR_ERR(dcp->rtk),
510515
"Failed to intialize RTKit");
511516

512-
ret = devm_pm_runtime_enable(dev);
517+
/* calling pm_runtime_force_resume() is equivalent to pm_runtime_enable
518+
* if pm_runtime_force_suspend was not previously called
519+
*/
520+
ret = pm_runtime_force_resume(dev);
513521
if (ret)
514-
return ret;
522+
dev_err_probe(dev, ret, "pm_runtime_force_resume failed!\n");
515523

516524
ret = pm_runtime_resume_and_get(dev);
517-
if (ret)
518-
return ret;
525+
if (ret) {
526+
devm_apple_rtkit_free(dev, dcp->rtk);
527+
dcp->rtk = NULL;
528+
return dev_err_probe(dev, ret, "pm_runtime_resume_and_get failed!\n");
529+
}
519530

520531
pm_runtime_set_autosuspend_delay(dev, 50);
521532
pm_runtime_use_autosuspend(dev);
@@ -542,15 +553,37 @@ static int dcp_comp_bind(struct device *dev, struct device *main, void *data)
542553
static void dcp_comp_unbind(struct device *dev, struct device *main, void *data)
543554
{
544555
struct apple_dcp *dcp = dev_get_drvdata(dev);
556+
int ret;
557+
558+
/*
559+
* Get device but limit resume to RTKit
560+
*/
561+
dcp->iomfb_started = false;
562+
ret = pm_runtime_resume_and_get(dev);
563+
if (ret)
564+
dev_err(dev, "pm_runtime_resume_and_get failed: %d\n", ret);
565+
pm_runtime_dont_use_autosuspend(dev);
566+
567+
/*
568+
* force_suspend and shutdown RTKit
569+
*/
570+
dcp->active = true;
571+
dcp->shutdown = true;
572+
573+
ret = pm_runtime_force_suspend(dev);
574+
if (ret)
575+
dev_err(dev, "pm_runtime_put_sync_suspend failed: %d\n", ret);
545576

546-
if (dcp && dcp->shmem)
547-
iomfb_shutdown(dcp);
577+
dcp->rtk = NULL;
578+
579+
dcp->shutdown = false;
580+
dcp->active = false;
548581

549582
platform_device_put(dcp->piodma);
550583
dcp->piodma = NULL;
551-
552-
devm_clk_put(dev, dcp->clk);
553584
dcp->clk = NULL;
585+
dcp->coproc_reg = NULL;
586+
iomfb_stop_rtkit(dcp);
554587
}
555588

556589
static const struct component_ops dcp_comp_ops = {
@@ -563,11 +596,16 @@ static int dcp_platform_probe(struct platform_device *pdev)
563596
enum dcp_firmware_version fw_compat;
564597
struct device *dev = &pdev->dev;
565598
struct apple_dcp *dcp;
599+
int ret;
566600

567601
fw_compat = dcp_check_firmware_version(dev);
568602
if (fw_compat == DCP_FIRMWARE_UNKNOWN)
569603
return -ENODEV;
570604

605+
ret = devm_pm_runtime_enable(dev);
606+
if (ret)
607+
return ret;
608+
571609
dcp = devm_kzalloc(dev, sizeof(*dcp), GFP_KERNEL);
572610
if (!dcp)
573611
return -ENOMEM;
@@ -577,6 +615,11 @@ static int dcp_platform_probe(struct platform_device *pdev)
577615

578616
platform_set_drvdata(pdev, dcp);
579617

618+
/* force suspend for symmetry with dcp_comp_unbind */
619+
ret = pm_runtime_force_suspend(dev);
620+
if (ret)
621+
dev_err(dev, "pm_runtime_put_sync_suspend failed: %d\n", ret);
622+
580623
return component_add(&pdev->dev, &dcp_comp_ops);
581624
}
582625

@@ -598,9 +641,15 @@ static int __maybe_unused dcp_runtime_suspend(struct device *dev)
598641
u32 cpu_ctrl;
599642
int ret;
600643

644+
if (!dcp->rtk || !dcp->coproc_reg)
645+
return 0;
646+
601647
dcp_sleep(dcp);
602648

603-
ret = apple_rtkit_idle(dcp->rtk);
649+
if (dcp->shutdown)
650+
ret = apple_rtkit_shutdown(dcp->rtk);
651+
else
652+
ret = apple_rtkit_idle(dcp->rtk);
604653
if (ret) {
605654
dev_err(dev, "Failed to shut down RTKit: %d", ret);
606655
return ret;
@@ -622,12 +671,29 @@ static int __maybe_unused dcp_runtime_resume(struct device *dev)
622671
u32 cpu_ctrl;
623672
int ret;
624673

674+
if (!dcp->rtk || !dcp->coproc_reg)
675+
return -ENODEV;
676+
625677
cpu_ctrl =
626678
readl_relaxed(dcp->coproc_reg + APPLE_DCP_COPROC_CPU_CONTROL);
627679
writel_relaxed(cpu_ctrl | APPLE_DCP_COPROC_CPU_CONTROL_RUN,
628680
dcp->coproc_reg + APPLE_DCP_COPROC_CPU_CONTROL);
629681

630682
ret = apple_rtkit_wake(dcp->rtk);
683+
if (ret == -ETIME) {
684+
dev_err(dev, "RTKit wakeup timed out, trying reset. Please do not report bugs");
685+
add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
686+
687+
ret = reset_control_assert(dcp->reset);
688+
if (ret)
689+
dev_warn(dev, "reset_control_assert failed: %d\n", ret);
690+
691+
ret = reset_control_deassert(dcp->reset);
692+
if (ret)
693+
dev_warn(dev, "reset_control_deassert failed: %d\n", ret);
694+
695+
ret = apple_rtkit_wake(dcp->rtk);
696+
}
631697
if (ret) {
632698
dev_err(dev, "Failed to wake up RTKit: %d", ret);
633699
return ret;
@@ -651,9 +717,7 @@ static const struct of_device_id of_match[] = {
651717
};
652718
MODULE_DEVICE_TABLE(of, of_match);
653719

654-
static const struct dev_pm_ops dcp_pm_ops = {
655-
SET_RUNTIME_PM_OPS(dcp_runtime_suspend, dcp_runtime_resume, NULL)
656-
};
720+
DEFINE_RUNTIME_DEV_PM_OPS(dcp_pm_ops, dcp_runtime_suspend, dcp_runtime_resume, NULL);
657721

658722
static struct platform_driver dcp_driver = {
659723
.probe = dcp_platform_probe,

drivers/gpu/drm/apple/dcp.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ void dcp_set_dimensions(struct apple_dcp *dcp);
6464
void dcp_send_message(struct apple_dcp *dcp, u8 endpoint, u64 message);
6565

6666
int iomfb_start_rtkit(struct apple_dcp *dcp);
67-
void iomfb_shutdown(struct apple_dcp *dcp);
67+
void iomfb_stop_rtkit(struct apple_dcp *dcp);
6868
/* rtkit message handler for IOMFB messages */
6969
void iomfb_recv_msg(struct apple_dcp *dcp, u64 message);
7070

drivers/gpu/drm/apple/iomfb.c

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1972,45 +1972,68 @@ static void dcp_started(struct apple_dcp *dcp, void *data, void *cookie)
19721972
iomfb_get_color_remap_mode(dcp, false, &color_remap, init_1, cookie);
19731973
}
19741974

1975+
static void dcp_shmem_info(struct apple_dcp *dcp, u64 dcp_dva)
1976+
{
1977+
dma_addr_t shmem_iova;
1978+
1979+
if (dcp_dva != 0 && dcp->shmem_iova == (dcp_dva & ~dcp->asc_dram_mask))
1980+
return;
1981+
1982+
dcp->shmem = dma_alloc_coherent(dcp->dev, DCP_SHMEM_SIZE,
1983+
&dcp->shmem_iova, GFP_KERNEL);
1984+
1985+
shmem_iova = dcp->shmem_iova | dcp->asc_dram_mask;
1986+
dcp_send_message(dcp, IOMFB_ENDPOINT, dcpep_set_shmem(shmem_iova));
1987+
1988+
if (dcp_dva != 0)
1989+
dcp_send_message(dcp, IOMFB_ENDPOINT,
1990+
FIELD_PREP(IOMFB_MESSAGE_TYPE,
1991+
IOMFB_MESSAGE_TYPE_INITIALIZED));
1992+
}
1993+
19751994
void iomfb_recv_msg(struct apple_dcp *dcp, u64 message)
19761995
{
19771996
enum dcpep_type type = FIELD_GET(IOMFB_MESSAGE_TYPE, message);
19781997

1979-
if (type == IOMFB_MESSAGE_TYPE_INITIALIZED)
1998+
switch (type) {
1999+
case IOMFB_MESSAGE_TYPE_SET_SHMEM:
2000+
dcp_shmem_info(dcp, FIELD_GET(IOMFB_SHMEM_DVA, message));
2001+
break;
2002+
case IOMFB_MESSAGE_TYPE_INITIALIZED:
19802003
dcp_start_signal(dcp, false, dcp_started, NULL);
1981-
else if (type == IOMFB_MESSAGE_TYPE_MSG)
2004+
break;
2005+
case IOMFB_MESSAGE_TYPE_MSG:
19822006
dcpep_got_msg(dcp, message);
1983-
else
1984-
dev_warn(dcp->dev, "Ignoring unknown message %llx\n", message);
2007+
break;
2008+
default:
2009+
dev_warn(dcp->dev, "Ignoring unknown type:%x msg:%llx\n", type,
2010+
message);
2011+
break;
2012+
}
19852013
}
19862014

19872015
int iomfb_start_rtkit(struct apple_dcp *dcp)
19882016
{
1989-
dma_addr_t shmem_iova;
19902017
int ret;
19912018

19922019
ret = apple_rtkit_start_ep(dcp->rtk, IOMFB_ENDPOINT);
19932020
if (ret < 0)
19942021
return ret;
19952022

1996-
dcp->shmem = dma_alloc_coherent(dcp->dev, DCP_SHMEM_SIZE, &shmem_iova,
1997-
GFP_KERNEL);
1998-
1999-
shmem_iova |= dcp->asc_dram_mask;
2000-
dcp_send_message(dcp, IOMFB_ENDPOINT, dcpep_set_shmem(shmem_iova));
2023+
/*
2024+
* Query current shared memory IOVA used for iomfb message passing
2025+
*/
2026+
dcp_send_message(dcp, IOMFB_ENDPOINT,
2027+
FIELD_PREP(IOMFB_MESSAGE_TYPE, IOMFB_MESSAGE_TYPE_SET_SHMEM) |
2028+
FIELD_PREP(IOMFB_SHMEM_FLAG, 0)
2029+
);
20012030

20022031
return 0;
20032032
}
20042033

2005-
void iomfb_shutdown(struct apple_dcp *dcp)
2034+
void iomfb_stop_rtkit(struct apple_dcp *dcp)
20062035
{
2007-
struct dcp_set_power_state_req req = {
2008-
/* defaults are ok */
2009-
};
2010-
2011-
/* We're going down */
2012-
dcp->active = false;
2013-
dcp->valid_mode = false;
2014-
2015-
dcp_set_power_state(dcp, false, &req, NULL, NULL);
2036+
dma_free_coherent(dcp->dev, DCP_SHMEM_SIZE, dcp->shmem, dcp->shmem_iova);
2037+
dcp->shmem = NULL;
2038+
dcp->shmem_iova = 0;
20162039
}

0 commit comments

Comments
 (0)