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+
479577static 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 ;
0 commit comments