Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions drivers/gpu/drm/apple/iomfb_v14_7.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ static const struct dcp_v14_board dcp_v14_board_t6030 = {
.handoff = "apple,t6030-handoff",
.promotion = true,
.panel_nits = true,
/* Measured on the J514S: DPMS off stops the panel's display controller. */
.panel_hw_off = true,
};

/*
Expand Down Expand Up @@ -311,7 +313,7 @@ struct apple_dcp_v14 {

static bool panel_hw_off = true;
module_param(panel_hw_off, bool, 0644);
MODULE_PARM_DESC(panel_hw_off, "Internal 14.7 panel: stop its display controller on DPMS off, not only blank it [default: true]");
MODULE_PARM_DESC(panel_hw_off, "Internal 14.7 panel of the J514S/J516S: stop its display controller on DPMS off, not only blank it [default: true]");

/*
* The panel's DCP session; one per boot, RTKit is never started twice. The
Expand All @@ -331,6 +333,17 @@ static bool dcp_v14_board_nits(const struct apple_dcp_v14 *v14)
return !v14->external && v14->panel_nits && v14->board && v14->board->panel_nits;
}

/*
* The panel whose display controller DPMS off stops, and which answers the
* callbacks of that transition: one with levels on a board record that asks
* for it (T6030: J514S, J516S). A record that has levels without the flag
* only blanks its panel.
*/
static bool dcp_v14_board_hw_off(const struct apple_dcp_v14 *v14)
{
return dcp_v14_board_nits(v14) && v14->board->panel_hw_off;
}

bool iomfb_v14_7_panel_nits(struct apple_dcp *dcp)
{
return dcp_is_v14_7_panel(dcp) && dcp->v14 && dcp_v14_board_nits(dcp->v14);
Expand Down Expand Up @@ -1165,11 +1178,11 @@ static int dcp_v14_callback(void *cookie, u32 tag, const void *input, u32 in_siz
* at power on, which the backlight restore after A472(1) answers. Only
* the J514S/J516S panel sends A472 so; elsewhere these stay unhandled.
*/
if (dcp_v14_board_nits(v14) &&
if (dcp_v14_board_hw_off(v14) &&
((tag == D(2) && SHAPE(0, 0)) || (tag == D(591) && SHAPE(20, 0)) ||
(tag == D(593) && SHAPE(4, 0))))
return 0;
if (dcp_v14_board_nits(v14) && (tag == D(574) || tag == D(700)) && SHAPE(4, 4)) {
if (dcp_v14_board_hw_off(v14) && (tag == D(574) || tag == D(700)) && SHAPE(4, 4)) {
if (tag == D(574) && in[0] > 1)
return -EINVAL;
put_unaligned_le32(0, out);
Expand Down Expand Up @@ -3453,7 +3466,7 @@ void iomfb_v14_7_poweroff(struct apple_dcp *dcp)
* Only the J514S/J516S panel, the one this was measured on, and only
* on DPMS off: suspend-to-idle cuts that power itself.
*/
if (!panel_hw_off || !dcp_v14_board_nits(v14) || dcp_v14_system_sleep())
if (!panel_hw_off || !dcp_v14_board_hw_off(v14) || dcp_v14_system_sleep())
return;
mutex_lock(&v14->lock);
if (!v14->panel_off && !READ_ONCE(v14->failed) && !READ_ONCE(dcp->crashed) &&
Expand Down
75 changes: 73 additions & 2 deletions drivers/gpu/drm/apple/iomfb_v14_7_backlight_lifetime_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,15 +153,16 @@ static const struct drm_framebuffer_funcs v14_bl_fb_funcs = {
.destroy = v14_bl_fb_destroy,
};

static struct v14_bl_rpc *v14_bl_rpc_setup(struct kunit *test)
static struct v14_bl_rpc *v14_bl_rpc_setup_board(struct kunit *test,
const struct dcp_v14_board *board)
{
struct v14_bl_rpc *c = kunit_kzalloc(test, sizeof(*c), GFP_KERNEL);
struct device *dev;
unsigned int i;

KUNIT_ASSERT_NOT_NULL(test, c);
c->test = test;
c->f = v14_bl_fixture(test, &dcp_v14_board_t6030, true);
c->f = v14_bl_fixture(test, board, true);
dev = drm_kunit_helper_alloc_device(test);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
c->drm = __drm_kunit_helper_alloc_drm_device(test, dev, sizeof(*c->drm), 0,
Expand Down Expand Up @@ -200,6 +201,11 @@ static struct v14_bl_rpc *v14_bl_rpc_setup(struct kunit *test)
return c;
}

static struct v14_bl_rpc *v14_bl_rpc_setup(struct kunit *test)
{
return v14_bl_rpc_setup_board(test, &dcp_v14_board_t6030);
}

static struct v14_bl_actor *v14_bl_actor_start(struct kunit *test,
struct v14_bl_rpc *c, unsigned int slot,
unsigned int op)
Expand Down Expand Up @@ -356,6 +362,69 @@ static void v14_bl_dpms_blank_only(struct kunit *test)
KUNIT_EXPECT_FALSE(test, c->f.v14->panel_off);
}

/* The T6030 record with levels but without panel_hw_off, as the J516C one would be. */
static struct dcp_v14_board *v14_bl_levels_board(struct kunit *test)
{
struct dcp_v14_board *board = kunit_kzalloc(test, sizeof(*board), GFP_KERNEL);

KUNIT_ASSERT_NOT_NULL(test, board);
*board = dcp_v14_board_t6030;
board->panel_hw_off = false;
return board;
}

/*
* A board record with levels but without panel_hw_off, as the J516C one
* would be with its panel levels: DPMS off only blanks the panel, and power
* on has no display controller to restart.
*/
static void v14_bl_dpms_levels_blank_only(struct kunit *test)
{
struct v14_bl_rpc *c = v14_bl_rpc_setup_board(test, v14_bl_levels_board(test));
struct platform_device *pdev = kunit_kzalloc(test, sizeof(*pdev), GFP_KERNEL);

KUNIT_ASSERT_NOT_NULL(test, pdev);
KUNIT_ASSERT_TRUE(test, iomfb_v14_7_panel_nits(c->f.dcp));
KUNIT_ASSERT_TRUE(test, panel_hw_off);
platform_set_drvdata(pdev, c->f.dcp);
KUNIT_ASSERT_TRUE(test, dcp_v14_present(c->f.v14, &c->fb[0], 64, 64, 0, NULL));
dcp_poweroff(pdev);
KUNIT_EXPECT_EQ(test, atomic_read(&c->submits), 2);
KUNIT_EXPECT_PTR_EQ(test, c->f.v14->active_fb, NULL);
KUNIT_EXPECT_EQ(test, c->power_calls, 0U);
KUNIT_EXPECT_FALSE(test, c->f.v14->panel_off);
dcp_poweron(pdev);
KUNIT_EXPECT_EQ(test, c->power_calls, 0U);
KUNIT_EXPECT_FALSE(test, c->f.v14->panel_off);
}

/*
* The callbacks of the A472 transitions are answered where DPMS off sends
* A472, on the T6030 record, and stay unhandled on a record with levels
* alone.
*/
static void v14_bl_hw_off_callbacks(struct kunit *test)
{
static const struct {
u32 tag, in_size, out_size;
} cbs[] = {
{ D(2), 0, 0 }, { D(591), 20, 0 }, { D(593), 4, 0 },
{ D(574), 4, 4 }, { D(700), 4, 4 },
};
struct v14_bl_fixture t6030 = v14_bl_fixture(test, &dcp_v14_board_t6030, false);
struct v14_bl_fixture levels = v14_bl_fixture(test, v14_bl_levels_board(test), false);
u8 in[20] = {}, out[4];
unsigned int i;

KUNIT_ASSERT_TRUE(test, dcp_v14_board_nits(levels.v14));
for (i = 0; i < ARRAY_SIZE(cbs); i++) {
KUNIT_EXPECT_EQ(test, dcp_v14_callback(t6030.v14, cbs[i].tag, in, cbs[i].in_size,
out, cbs[i].out_size), 0);
KUNIT_EXPECT_EQ(test, dcp_v14_callback(levels.v14, cbs[i].tag, in, cbs[i].in_size,
out, cbs[i].out_size), -EOPNOTSUPP);
}
}

static bool v14_bl_in_system_sleep(void)
{
return true;
Expand Down Expand Up @@ -516,6 +585,8 @@ static struct kunit_case v14_bl_lifetime_cases[] = {
KUNIT_CASE(v14_bl_running_work_suspend),
KUNIT_CASE(v14_bl_dpms_dispatch),
KUNIT_CASE(v14_bl_dpms_blank_only),
KUNIT_CASE(v14_bl_dpms_levels_blank_only),
KUNIT_CASE(v14_bl_hw_off_callbacks),
KUNIT_CASE(v14_bl_sleep_blank_only),
KUNIT_CASE(v14_bl_power_on_refused),
KUNIT_CASE(v14_bl_failed_submit_unknown),
Expand Down
7 changes: 7 additions & 0 deletions drivers/gpu/drm/apple/iomfb_v14_7_board.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ struct dcp_v14_board {
bool swap_timestamps;
/* This board has a qualified panel level block; machine admission is separate. */
bool panel_nits;
/*
* DPMS off may stop the panel's display controller (A472 with the
* hardware-power selector), not only blank it, and the callbacks of
* that transition are answered. Only where that was measured: a record
* with levels need not have it.
*/
bool panel_hw_off;
};

/* Whether the DCP node or the machine (as @ctx gives them) has @compat. */
Expand Down
6 changes: 6 additions & 0 deletions drivers/gpu/drm/apple/v14-board-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ static void v14_board_j516c(struct kunit *test)
KUNIT_EXPECT_EQ(test, b->ctm_set, 0);
KUNIT_EXPECT_EQ(test, b->ctm_get, 0);
KUNIT_EXPECT_TRUE(test, b->base_edid);
/* DPMS off only blanks its panel. */
KUNIT_EXPECT_FALSE(test, b->panel_hw_off);
}

/*
Expand All @@ -102,6 +104,7 @@ static void v14_board_j514c(struct kunit *test)
KUNIT_EXPECT_EQ(test, b->ctm_set, 0);
/* Its panel is not the J516C's: no base EDID. */
KUNIT_EXPECT_FALSE(test, b->base_edid);
KUNIT_EXPECT_FALSE(test, b->panel_hw_off);
KUNIT_EXPECT_TRUE(test, dcp_v14_board_admits(b, J516C_DCP_IMAGE));
KUNIT_EXPECT_FALSE(test, dcp_v14_board_admits(b, T6030_DCP_IMAGE));
/* Not the J516C record. */
Expand Down Expand Up @@ -161,6 +164,8 @@ static void v14_board_unchanged(struct kunit *test)
KUNIT_EXPECT_FALSE(test, b->log_bringup);
KUNIT_EXPECT_EQ(test, b->ctm_set, 0);
KUNIT_EXPECT_FALSE(test, b->base_edid);
/* The J514S/J516S panel, on which DPMS off stops the display controller. */
KUNIT_EXPECT_TRUE(test, b->panel_hw_off);
KUNIT_EXPECT_TRUE(test, dcp_v14_board_admits(b, T6030_DCP_IMAGE));
KUNIT_EXPECT_FALSE(test, dcp_v14_board_admits(b, J613_DCP_IMAGE));
/* The T6030 record serves a T6030 DCP on any machine, as before. */
Expand All @@ -176,6 +181,7 @@ static void v14_board_unchanged(struct kunit *test)
KUNIT_EXPECT_FALSE(test, b->promotion);
KUNIT_EXPECT_FALSE(test, b->log_bringup);
KUNIT_EXPECT_FALSE(test, b->base_edid);
KUNIT_EXPECT_FALSE(test, b->panel_hw_off);
KUNIT_EXPECT_FALSE(test, dcp_v14_board_admits(b, T6030_DCP_IMAGE));

/* A T8122 DCP on a T6031 machine has no record. */
Expand Down