Skip to content

Commit 00f0043

Browse files
jannaumarcan
authored andcommitted
drm: apple: Move offsets for rt_bandwidth callback to DT
The offsets differ for every DCP instance. Instead of hardcoding offsets for each SoC family offsets and calculate the instance offset move everything to the device tree. This helps multi die SoCs since there is and unexpected offset between both dies. On multi die SoCs device tree changes were necessary to avoid translating the PMGR reg via the seconds die "ranges" property. Signed-off-by: Janne Grunau <j@jannau.net>
1 parent f4f07ee commit 00f0043

3 files changed

Lines changed: 151 additions & 30 deletions

File tree

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <linux/backlight.h>
88
#include <linux/device.h>
9+
#include <linux/ioport.h>
910
#include <linux/mutex.h>
1011
#include <linux/mux/consumer.h>
1112
#include <linux/phy/phy.h>
@@ -136,6 +137,13 @@ struct apple_dcp {
136137
struct resource *disp_registers[MAX_DISP_REGISTERS];
137138
unsigned int nr_disp_registers;
138139

140+
struct resource disp_bw_scratch_res;
141+
struct resource disp_bw_doorbell_res;
142+
u32 disp_bw_scratch_index;
143+
u32 disp_bw_scratch_offset;
144+
u32 disp_bw_doorbell_index;
145+
u32 disp_bw_doorbell_offset;
146+
139147
u32 index;
140148

141149
/* Bitmap of memory descriptors used for mappings made by the DCP */

drivers/gpu/drm/apple/dcp.c

Lines changed: 121 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/kernel.h>
1515
#include <linux/module.h>
1616
#include <linux/moduleparam.h>
17+
#include <linux/of_address.h>
1718
#include <linux/of_device.h>
1819
#include <linux/of_platform.h>
1920
#include <linux/slab.h>
@@ -476,11 +477,108 @@ static int dcp_create_piodma_iommu_dev(struct apple_dcp *dcp)
476477
return ret;
477478
}
478479

480+
static int dcp_get_bw_scratch_reg(struct apple_dcp *dcp, u32 expected)
481+
{
482+
struct of_phandle_args ph_args;
483+
u32 addr_idx, disp_idx, offset;
484+
int ret;
485+
486+
ret = of_parse_phandle_with_args(dcp->dev->of_node, "apple,bw-scratch",
487+
"#apple,bw-scratch-cells", 0, &ph_args);
488+
if (ret < 0) {
489+
dev_err(dcp->dev, "Failed to read 'apple,bw-scratch': %d\n", ret);
490+
return ret;
491+
}
492+
493+
if (ph_args.args_count != 3) {
494+
dev_err(dcp->dev, "Unexpected 'apple,bw-scratch' arg count %d\n",
495+
ph_args.args_count);
496+
ret = -EINVAL;
497+
goto err_of_node_put;
498+
}
499+
500+
addr_idx = ph_args.args[0];
501+
disp_idx = ph_args.args[1];
502+
offset = ph_args.args[2];
503+
504+
if (disp_idx != expected || disp_idx >= MAX_DISP_REGISTERS) {
505+
dev_err(dcp->dev, "Unexpected disp_reg value in 'apple,bw-scratch': %d\n",
506+
disp_idx);
507+
ret = -EINVAL;
508+
goto err_of_node_put;
509+
}
510+
511+
ret = of_address_to_resource(ph_args.np, addr_idx, &dcp->disp_bw_scratch_res);
512+
if (ret < 0) {
513+
dev_err(dcp->dev, "Failed to get 'apple,bw-scratch' resource %d from %pOF\n",
514+
addr_idx, ph_args.np);
515+
goto err_of_node_put;
516+
}
517+
if (offset > resource_size(&dcp->disp_bw_scratch_res) - 4) {
518+
ret = -EINVAL;
519+
goto err_of_node_put;
520+
}
521+
522+
dcp->disp_registers[disp_idx] = &dcp->disp_bw_scratch_res;
523+
dcp->disp_bw_scratch_index = disp_idx;
524+
dcp->disp_bw_scratch_offset = offset;
525+
ret = 0;
526+
527+
err_of_node_put:
528+
of_node_put(ph_args.np);
529+
return ret;
530+
}
531+
532+
static int dcp_get_bw_doorbell_reg(struct apple_dcp *dcp, u32 expected)
533+
{
534+
struct of_phandle_args ph_args;
535+
u32 addr_idx, disp_idx;
536+
int ret;
537+
538+
ret = of_parse_phandle_with_args(dcp->dev->of_node, "apple,bw-doorbell",
539+
"#apple,bw-doorbell-cells", 0, &ph_args);
540+
if (ret < 0) {
541+
dev_err(dcp->dev, "Failed to read 'apple,bw-doorbell': %d\n", ret);
542+
return ret;
543+
}
544+
545+
if (ph_args.args_count != 2) {
546+
dev_err(dcp->dev, "Unexpected 'apple,bw-doorbell' arg count %d\n",
547+
ph_args.args_count);
548+
ret = -EINVAL;
549+
goto err_of_node_put;
550+
}
551+
552+
addr_idx = ph_args.args[0];
553+
disp_idx = ph_args.args[1];
554+
555+
if (disp_idx != expected || disp_idx >= MAX_DISP_REGISTERS) {
556+
dev_err(dcp->dev, "Unexpected disp_reg value in 'apple,bw-doorbell': %d\n",
557+
disp_idx);
558+
ret = -EINVAL;
559+
goto err_of_node_put;
560+
}
561+
562+
ret = of_address_to_resource(ph_args.np, addr_idx, &dcp->disp_bw_doorbell_res);
563+
if (ret < 0) {
564+
dev_err(dcp->dev, "Failed to get 'apple,bw-doorbell' resource %d from %pOF\n",
565+
addr_idx, ph_args.np);
566+
goto err_of_node_put;
567+
}
568+
dcp->disp_bw_doorbell_index = disp_idx;
569+
dcp->disp_registers[disp_idx] = &dcp->disp_bw_doorbell_res;
570+
ret = 0;
571+
572+
err_of_node_put:
573+
of_node_put(ph_args.np);
574+
return ret;
575+
}
576+
479577
static int dcp_get_disp_regs(struct apple_dcp *dcp)
480578
{
481579
struct platform_device *pdev = to_platform_device(dcp->dev);
482580
int count = pdev->num_resources - 1;
483-
int i;
581+
int i, ret;
484582

485583
if (count <= 0 || count > MAX_DISP_REGISTERS)
486584
return -EINVAL;
@@ -490,6 +588,20 @@ static int dcp_get_disp_regs(struct apple_dcp *dcp)
490588
platform_get_resource(pdev, IORESOURCE_MEM, 1 + i);
491589
}
492590

591+
/* load pmgr bandwidth scratch resource and offset */
592+
ret = dcp_get_bw_scratch_reg(dcp, count);
593+
if (ret < 0)
594+
return ret;
595+
count += 1;
596+
597+
/* load pmgr bandwidth doorbell resource if present (only on t8103) */
598+
if (of_property_present(dcp->dev->of_node, "apple,bw-doorbell")) {
599+
ret = dcp_get_bw_doorbell_reg(dcp, count);
600+
if (ret < 0)
601+
return ret;
602+
count += 1;
603+
}
604+
493605
dcp->nr_disp_registers = count;
494606
return 0;
495607
}
@@ -728,6 +840,14 @@ static int dcp_platform_probe(struct platform_device *pdev)
728840
if (fw_compat == DCP_FIRMWARE_UNKNOWN)
729841
return -ENODEV;
730842

843+
/* Check for "apple,bw-scratch" to avoid probing appledrm with outdated
844+
* device trees. This prevents replacing simpledrm and ending up without
845+
* display.
846+
*/
847+
if (!of_property_present(dev->of_node, "apple,bw-scratch"))
848+
return dev_err_probe(dev, -ENODEV, "Incompatible devicetree! "
849+
"Use devicetree matching this kernel.\n");
850+
731851
dcp = devm_kzalloc(dev, sizeof(*dcp), GFP_KERNEL);
732852
if (!dcp)
733853
return -ENOMEM;

drivers/gpu/drm/apple/iomfb_template.c

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,7 @@
3333
#include "version_utils.h"
3434

3535
/* Register defines used in bandwidth setup structure */
36-
#define REG_SCRATCH (0x14)
37-
#define REG_SCRATCH_T600X (0x988)
38-
#define REG_SCRATCH_T602X (0x1208)
39-
#define REG_DOORBELL (0x0)
40-
#define REG_DOORBELL_BIT (2)
36+
#define REG_DOORBELL_BIT(idx) (2 + (idx))
4137

4238
struct dcp_wait_cookie {
4339
struct kref refcount;
@@ -665,34 +661,31 @@ static struct dcp_allocate_bandwidth_resp dcpep_cb_allocate_bandwidth(struct app
665661

666662
static struct dcp_rt_bandwidth dcpep_cb_rt_bandwidth(struct apple_dcp *dcp)
667663
{
668-
if (dcp->disp_registers[5] && dcp->disp_registers[6]) {
669-
return (struct dcp_rt_bandwidth){
670-
.reg_scratch =
671-
dcp->disp_registers[5]->start + REG_SCRATCH,
672-
.reg_doorbell =
673-
dcp->disp_registers[6]->start + REG_DOORBELL,
674-
.doorbell_bit = REG_DOORBELL_BIT,
675-
676-
.padding[3] = 0x4, // XXX: required by 11.x firmware
677-
};
678-
} else if (dcp->disp_registers[4]) {
679-
u32 offset = REG_SCRATCH_T600X;
680-
if (of_device_is_compatible(dcp->dev->of_node, "apple,t6020-dcp"))
681-
offset = REG_SCRATCH_T602X;
682-
683-
return (struct dcp_rt_bandwidth){
684-
.reg_scratch = dcp->disp_registers[4]->start +
685-
offset,
686-
.reg_doorbell = 0,
687-
.doorbell_bit = 0,
688-
};
689-
} else {
690-
return (struct dcp_rt_bandwidth){
664+
struct dcp_rt_bandwidth rt_bw = (struct dcp_rt_bandwidth){
691665
.reg_scratch = 0,
692666
.reg_doorbell = 0,
693667
.doorbell_bit = 0,
694-
};
668+
};
669+
670+
if (dcp->disp_bw_scratch_index) {
671+
u32 offset = dcp->disp_bw_scratch_offset;
672+
u32 index = dcp->disp_bw_scratch_index;
673+
rt_bw.reg_scratch = dcp->disp_registers[index]->start + offset;
695674
}
675+
676+
if (dcp->disp_bw_doorbell_index) {
677+
u32 index = dcp->disp_bw_doorbell_index;
678+
rt_bw.reg_doorbell = dcp->disp_registers[index]->start;
679+
rt_bw.doorbell_bit = REG_DOORBELL_BIT(dcp->index);
680+
/*
681+
* This is most certainly not padding. t8103-dcp crashes without
682+
* setting this immediately during modeset on 12.3 and 13.5
683+
* firmware.
684+
*/
685+
rt_bw.padding[3] = 0x4;
686+
}
687+
688+
return rt_bw;
696689
}
697690

698691
static struct dcp_set_frame_sync_props_resp

0 commit comments

Comments
 (0)