1818#include <linux/platform_device.h>
1919#include <linux/regmap.h>
2020
21+ #include <dt-bindings/clock/xlnx-vcu.h>
22+
2123/* vcu slcr registers, bitmask and shift */
2224#define VCU_PLL_CTRL 0x24
2325#define VCU_PLL_CTRL_RESET_MASK 0x01
5052#define VCU_ENC_MCU_CTRL 0x34
5153#define VCU_DEC_CORE_CTRL 0x38
5254#define VCU_DEC_MCU_CTRL 0x3c
53- #define VCU_PLL_DIVISOR_MASK 0x3f
54- #define VCU_PLL_DIVISOR_SHIFT 4
55- #define VCU_SRCSEL_MASK 0x01
56- #define VCU_SRCSEL_SHIFT 0
57- #define VCU_SRCSEL_PLL 1
5855
5956#define VCU_PLL_STATUS 0x60
6057#define VCU_PLL_STATUS_LOCK_STATUS_MASK 0x01
7572 * @logicore_reg_ba: logicore reg base address
7673 * @vcu_slcr_ba: vcu_slcr Register base address
7774 * @pll: handle for the VCU PLL
75+ * @clk_data: clocks provided by the vcu clock provider
7876 */
7977struct xvcu_device {
8078 struct device * dev ;
@@ -83,6 +81,7 @@ struct xvcu_device {
8381 struct regmap * logicore_reg_ba ;
8482 void __iomem * vcu_slcr_ba ;
8583 struct clk_hw * pll ;
84+ struct clk_hw_onecell_data * clk_data ;
8685};
8786
8887static struct regmap_config vcu_settings_regmap_config = {
@@ -404,7 +403,7 @@ static int xvcu_set_vcu_pll_info(struct xvcu_device *xvcu)
404403 u32 refclk , coreclk , mcuclk , inte , deci ;
405404 u32 divisor_mcu , divisor_core , fvco ;
406405 u32 clkoutdiv , vcu_pll_ctrl , pll_clk ;
407- u32 mod , ctrl ;
406+ u32 mod ;
408407 int i ;
409408 int ret ;
410409 const struct xvcu_pll_cfg * found = NULL ;
@@ -479,37 +478,6 @@ static int xvcu_set_vcu_pll_info(struct xvcu_device *xvcu)
479478 dev_dbg (xvcu -> dev , "Actual Core clock freq is %uHz\n" , coreclk );
480479 dev_dbg (xvcu -> dev , "Actual Mcu clock freq is %uHz\n" , mcuclk );
481480
482- /* Set divisor for the core and mcu clock */
483- ctrl = xvcu_read (xvcu -> vcu_slcr_ba , VCU_ENC_CORE_CTRL );
484- ctrl &= ~(VCU_PLL_DIVISOR_MASK << VCU_PLL_DIVISOR_SHIFT );
485- ctrl |= (divisor_core & VCU_PLL_DIVISOR_MASK ) <<
486- VCU_PLL_DIVISOR_SHIFT ;
487- ctrl &= ~(VCU_SRCSEL_MASK << VCU_SRCSEL_SHIFT );
488- ctrl |= (VCU_SRCSEL_PLL & VCU_SRCSEL_MASK ) << VCU_SRCSEL_SHIFT ;
489- xvcu_write (xvcu -> vcu_slcr_ba , VCU_ENC_CORE_CTRL , ctrl );
490-
491- ctrl = xvcu_read (xvcu -> vcu_slcr_ba , VCU_DEC_CORE_CTRL );
492- ctrl &= ~(VCU_PLL_DIVISOR_MASK << VCU_PLL_DIVISOR_SHIFT );
493- ctrl |= (divisor_core & VCU_PLL_DIVISOR_MASK ) <<
494- VCU_PLL_DIVISOR_SHIFT ;
495- ctrl &= ~(VCU_SRCSEL_MASK << VCU_SRCSEL_SHIFT );
496- ctrl |= (VCU_SRCSEL_PLL & VCU_SRCSEL_MASK ) << VCU_SRCSEL_SHIFT ;
497- xvcu_write (xvcu -> vcu_slcr_ba , VCU_DEC_CORE_CTRL , ctrl );
498-
499- ctrl = xvcu_read (xvcu -> vcu_slcr_ba , VCU_ENC_MCU_CTRL );
500- ctrl &= ~(VCU_PLL_DIVISOR_MASK << VCU_PLL_DIVISOR_SHIFT );
501- ctrl |= (divisor_mcu & VCU_PLL_DIVISOR_MASK ) << VCU_PLL_DIVISOR_SHIFT ;
502- ctrl &= ~(VCU_SRCSEL_MASK << VCU_SRCSEL_SHIFT );
503- ctrl |= (VCU_SRCSEL_PLL & VCU_SRCSEL_MASK ) << VCU_SRCSEL_SHIFT ;
504- xvcu_write (xvcu -> vcu_slcr_ba , VCU_ENC_MCU_CTRL , ctrl );
505-
506- ctrl = xvcu_read (xvcu -> vcu_slcr_ba , VCU_DEC_MCU_CTRL );
507- ctrl &= ~(VCU_PLL_DIVISOR_MASK << VCU_PLL_DIVISOR_SHIFT );
508- ctrl |= (divisor_mcu & VCU_PLL_DIVISOR_MASK ) << VCU_PLL_DIVISOR_SHIFT ;
509- ctrl &= ~(VCU_SRCSEL_MASK << VCU_SRCSEL_SHIFT );
510- ctrl |= (VCU_SRCSEL_PLL & VCU_SRCSEL_MASK ) << VCU_SRCSEL_SHIFT ;
511- xvcu_write (xvcu -> vcu_slcr_ba , VCU_DEC_MCU_CTRL , ctrl );
512-
513481 ret = xvcu_pll_set_rate (xvcu , fvco , refclk );
514482 if (ret )
515483 return ret ;
@@ -546,6 +514,151 @@ static int xvcu_set_pll(struct xvcu_device *xvcu)
546514 return xvcu_pll_enable (xvcu );
547515}
548516
517+ static struct clk_hw * xvcu_clk_hw_register_leaf (struct device * dev ,
518+ const char * name ,
519+ const struct clk_parent_data * parent_data ,
520+ u8 num_parents ,
521+ void __iomem * reg )
522+ {
523+ u8 mux_flags = CLK_MUX_ROUND_CLOSEST ;
524+ u8 divider_flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO |
525+ CLK_DIVIDER_ROUND_CLOSEST ;
526+ struct clk_hw * mux = NULL ;
527+ struct clk_hw * divider = NULL ;
528+ struct clk_hw * gate = NULL ;
529+ char * name_mux ;
530+ char * name_div ;
531+ int err ;
532+ /* Protect register shared by clocks */
533+ spinlock_t * lock ;
534+
535+ lock = devm_kzalloc (dev , sizeof (* lock ), GFP_KERNEL );
536+ if (!lock )
537+ return ERR_PTR (- ENOMEM );
538+ spin_lock_init (lock );
539+
540+ name_mux = devm_kasprintf (dev , GFP_KERNEL , "%s%s" , name , "_mux" );
541+ if (!name_mux )
542+ return ERR_PTR (- ENOMEM );
543+ mux = clk_hw_register_mux_parent_data (dev , name_mux ,
544+ parent_data , num_parents ,
545+ CLK_SET_RATE_PARENT ,
546+ reg , 0 , 1 , mux_flags , lock );
547+ if (IS_ERR (mux ))
548+ return mux ;
549+
550+ name_div = devm_kasprintf (dev , GFP_KERNEL , "%s%s" , name , "_div" );
551+ if (!name_div ) {
552+ err = - ENOMEM ;
553+ goto unregister_mux ;
554+ }
555+ divider = clk_hw_register_divider_parent_hw (dev , name_div , mux ,
556+ CLK_SET_RATE_PARENT ,
557+ reg , 4 , 6 , divider_flags ,
558+ lock );
559+ if (IS_ERR (divider )) {
560+ err = PTR_ERR (divider );
561+ goto unregister_mux ;
562+ }
563+
564+ gate = clk_hw_register_gate_parent_hw (dev , name , divider ,
565+ CLK_SET_RATE_PARENT , reg , 12 , 0 ,
566+ lock );
567+ if (IS_ERR (gate )) {
568+ err = PTR_ERR (gate );
569+ goto unregister_divider ;
570+ }
571+
572+ return gate ;
573+
574+ unregister_divider :
575+ clk_hw_unregister_divider (divider );
576+ unregister_mux :
577+ clk_hw_unregister_mux (mux );
578+
579+ return ERR_PTR (err );
580+ }
581+
582+ static void xvcu_clk_hw_unregister_leaf (struct clk_hw * hw )
583+ {
584+ struct clk_hw * gate = hw ;
585+ struct clk_hw * divider ;
586+ struct clk_hw * mux ;
587+
588+ if (!gate )
589+ return ;
590+
591+ divider = clk_hw_get_parent (gate );
592+ clk_hw_unregister_gate (gate );
593+ if (!divider )
594+ return ;
595+
596+ mux = clk_hw_get_parent (divider );
597+ clk_hw_unregister_mux (mux );
598+ if (!divider )
599+ return ;
600+
601+ clk_hw_unregister_divider (divider );
602+ }
603+
604+ static int xvcu_register_clock_provider (struct xvcu_device * xvcu )
605+ {
606+ struct device * dev = xvcu -> dev ;
607+ struct clk_parent_data parent_data [2 ] = { 0 };
608+ struct clk_hw_onecell_data * data ;
609+ struct clk_hw * * hws ;
610+ void __iomem * reg_base = xvcu -> vcu_slcr_ba ;
611+
612+ data = devm_kzalloc (dev , struct_size (data , hws , CLK_XVCU_NUM_CLOCKS ), GFP_KERNEL );
613+ if (!data )
614+ return - ENOMEM ;
615+ data -> num = CLK_XVCU_NUM_CLOCKS ;
616+ hws = data -> hws ;
617+
618+ xvcu -> clk_data = data ;
619+
620+ parent_data [0 ].fw_name = "pll_ref" ;
621+ parent_data [1 ].hw = xvcu -> pll ;
622+
623+ hws [CLK_XVCU_ENC_CORE ] =
624+ xvcu_clk_hw_register_leaf (dev , "venc_core_clk" ,
625+ parent_data ,
626+ ARRAY_SIZE (parent_data ),
627+ reg_base + VCU_ENC_CORE_CTRL );
628+ hws [CLK_XVCU_ENC_MCU ] =
629+ xvcu_clk_hw_register_leaf (dev , "venc_mcu_clk" ,
630+ parent_data ,
631+ ARRAY_SIZE (parent_data ),
632+ reg_base + VCU_ENC_MCU_CTRL );
633+ hws [CLK_XVCU_DEC_CORE ] =
634+ xvcu_clk_hw_register_leaf (dev , "vdec_core_clk" ,
635+ parent_data ,
636+ ARRAY_SIZE (parent_data ),
637+ reg_base + VCU_DEC_CORE_CTRL );
638+ hws [CLK_XVCU_DEC_MCU ] =
639+ xvcu_clk_hw_register_leaf (dev , "vdec_mcu_clk" ,
640+ parent_data ,
641+ ARRAY_SIZE (parent_data ),
642+ reg_base + VCU_DEC_MCU_CTRL );
643+
644+ return devm_of_clk_add_hw_provider (dev , of_clk_hw_onecell_get , data );
645+ }
646+
647+ static void xvcu_unregister_clock_provider (struct xvcu_device * xvcu )
648+ {
649+ struct clk_hw_onecell_data * data = xvcu -> clk_data ;
650+ struct clk_hw * * hws = data -> hws ;
651+
652+ if (!IS_ERR_OR_NULL (hws [CLK_XVCU_DEC_MCU ]))
653+ xvcu_clk_hw_unregister_leaf (hws [CLK_XVCU_DEC_MCU ]);
654+ if (!IS_ERR_OR_NULL (hws [CLK_XVCU_DEC_CORE ]))
655+ xvcu_clk_hw_unregister_leaf (hws [CLK_XVCU_DEC_CORE ]);
656+ if (!IS_ERR_OR_NULL (hws [CLK_XVCU_ENC_MCU ]))
657+ xvcu_clk_hw_unregister_leaf (hws [CLK_XVCU_ENC_MCU ]);
658+ if (!IS_ERR_OR_NULL (hws [CLK_XVCU_ENC_CORE ]))
659+ xvcu_clk_hw_unregister_leaf (hws [CLK_XVCU_ENC_CORE ]);
660+ }
661+
549662/**
550663 * xvcu_probe - Probe existence of the logicoreIP
551664 * and initialize PLL
@@ -640,10 +753,18 @@ static int xvcu_probe(struct platform_device *pdev)
640753 goto error_pll_ref ;
641754 }
642755
756+ ret = xvcu_register_clock_provider (xvcu );
757+ if (ret ) {
758+ dev_err (& pdev -> dev , "failed to register clock provider\n" );
759+ goto error_clk_provider ;
760+ }
761+
643762 dev_set_drvdata (& pdev -> dev , xvcu );
644763
645764 return 0 ;
646765
766+ error_clk_provider :
767+ xvcu_unregister_clock_provider (xvcu );
647768error_pll_ref :
648769 clk_disable_unprepare (xvcu -> aclk );
649770 return ret ;
@@ -665,6 +786,8 @@ static int xvcu_remove(struct platform_device *pdev)
665786 if (!xvcu )
666787 return - ENODEV ;
667788
789+ xvcu_unregister_clock_provider (xvcu );
790+
668791 /* Add the the Gasket isolation and put the VCU in reset. */
669792 regmap_write (xvcu -> logicore_reg_ba , VCU_GASKET_INIT , 0 );
670793
0 commit comments