aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXing Zheng <zhengxing@rock-chips.com>2016-03-09 22:47:01 -0500
committerHeiko Stuebner <heiko@sntech.de>2016-03-27 07:03:34 -0400
commitb40baccd236a9a91fbb077efb8dadb41fdfb55ab (patch)
treefc509c8e9614fea595fb285467e606f5a04de850
parentef1d9feeccc094f59b72bb11fe14ec886eb574d3 (diff)
clk: rockchip: add new pll-type for rk3399 and similar socs
The rk3399's pll and clock are similar with rk3036's, it different with base on the rk3066(rk3188, rk3288, rk3368 use it), there are different adjust foctors and control registers, so these should be independent and separate from the series of rk3066s. Signed-off-by: Xing Zheng <zhengxing@rock-chips.com> Signed-off-by: Heiko Stuebner <heiko@sntech.de>
-rw-r--r--drivers/clk/rockchip/clk-pll.c271
-rw-r--r--drivers/clk/rockchip/clk.h3
2 files changed, 272 insertions, 2 deletions
diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
index 27be66a2a358..128a6b2fca7f 100644
--- a/drivers/clk/rockchip/clk-pll.c
+++ b/drivers/clk/rockchip/clk-pll.c
@@ -593,6 +593,267 @@ static const struct clk_ops rockchip_rk3066_pll_clk_ops = {
593 .init = rockchip_rk3066_pll_init, 593 .init = rockchip_rk3066_pll_init,
594}; 594};
595 595
596/**
597 * PLL used in RK3399
598 */
599
600#define RK3399_PLLCON(i) (i * 0x4)
601#define RK3399_PLLCON0_FBDIV_MASK 0xfff
602#define RK3399_PLLCON0_FBDIV_SHIFT 0
603#define RK3399_PLLCON1_REFDIV_MASK 0x3f
604#define RK3399_PLLCON1_REFDIV_SHIFT 0
605#define RK3399_PLLCON1_POSTDIV1_MASK 0x7
606#define RK3399_PLLCON1_POSTDIV1_SHIFT 8
607#define RK3399_PLLCON1_POSTDIV2_MASK 0x7
608#define RK3399_PLLCON1_POSTDIV2_SHIFT 12
609#define RK3399_PLLCON2_FRAC_MASK 0xffffff
610#define RK3399_PLLCON2_FRAC_SHIFT 0
611#define RK3399_PLLCON2_LOCK_STATUS BIT(31)
612#define RK3399_PLLCON3_PWRDOWN BIT(0)
613#define RK3399_PLLCON3_DSMPD_MASK 0x1
614#define RK3399_PLLCON3_DSMPD_SHIFT 3
615
616static int rockchip_rk3399_pll_wait_lock(struct rockchip_clk_pll *pll)
617{
618 u32 pllcon;
619 int delay = 24000000;
620
621 /* poll check the lock status in rk3399 xPLLCON2 */
622 while (delay > 0) {
623 pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(2));
624 if (pllcon & RK3399_PLLCON2_LOCK_STATUS)
625 return 0;
626
627 delay--;
628 }
629
630 pr_err("%s: timeout waiting for pll to lock\n", __func__);
631 return -ETIMEDOUT;
632}
633
634static void rockchip_rk3399_pll_get_params(struct rockchip_clk_pll *pll,
635 struct rockchip_pll_rate_table *rate)
636{
637 u32 pllcon;
638
639 pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(0));
640 rate->fbdiv = ((pllcon >> RK3399_PLLCON0_FBDIV_SHIFT)
641 & RK3399_PLLCON0_FBDIV_MASK);
642
643 pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(1));
644 rate->refdiv = ((pllcon >> RK3399_PLLCON1_REFDIV_SHIFT)
645 & RK3399_PLLCON1_REFDIV_MASK);
646 rate->postdiv1 = ((pllcon >> RK3399_PLLCON1_POSTDIV1_SHIFT)
647 & RK3399_PLLCON1_POSTDIV1_MASK);
648 rate->postdiv2 = ((pllcon >> RK3399_PLLCON1_POSTDIV2_SHIFT)
649 & RK3399_PLLCON1_POSTDIV2_MASK);
650
651 pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(2));
652 rate->frac = ((pllcon >> RK3399_PLLCON2_FRAC_SHIFT)
653 & RK3399_PLLCON2_FRAC_MASK);
654
655 pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(3));
656 rate->dsmpd = ((pllcon >> RK3399_PLLCON3_DSMPD_SHIFT)
657 & RK3399_PLLCON3_DSMPD_MASK);
658}
659
660static unsigned long rockchip_rk3399_pll_recalc_rate(struct clk_hw *hw,
661 unsigned long prate)
662{
663 struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
664 struct rockchip_pll_rate_table cur;
665 u64 rate64 = prate;
666
667 rockchip_rk3399_pll_get_params(pll, &cur);
668
669 rate64 *= cur.fbdiv;
670 do_div(rate64, cur.refdiv);
671
672 if (cur.dsmpd == 0) {
673 /* fractional mode */
674 u64 frac_rate64 = prate * cur.frac;
675
676 do_div(frac_rate64, cur.refdiv);
677 rate64 += frac_rate64 >> 24;
678 }
679
680 do_div(rate64, cur.postdiv1);
681 do_div(rate64, cur.postdiv2);
682
683 return (unsigned long)rate64;
684}
685
686static int rockchip_rk3399_pll_set_params(struct rockchip_clk_pll *pll,
687 const struct rockchip_pll_rate_table *rate)
688{
689 const struct clk_ops *pll_mux_ops = pll->pll_mux_ops;
690 struct clk_mux *pll_mux = &pll->pll_mux;
691 struct rockchip_pll_rate_table cur;
692 u32 pllcon;
693 int rate_change_remuxed = 0;
694 int cur_parent;
695 int ret;
696
697 pr_debug("%s: rate settings for %lu fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
698 __func__, rate->rate, rate->fbdiv, rate->postdiv1, rate->refdiv,
699 rate->postdiv2, rate->dsmpd, rate->frac);
700
701 rockchip_rk3399_pll_get_params(pll, &cur);
702 cur.rate = 0;
703
704 cur_parent = pll_mux_ops->get_parent(&pll_mux->hw);
705 if (cur_parent == PLL_MODE_NORM) {
706 pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW);
707 rate_change_remuxed = 1;
708 }
709
710 /* update pll values */
711 writel_relaxed(HIWORD_UPDATE(rate->fbdiv, RK3399_PLLCON0_FBDIV_MASK,
712 RK3399_PLLCON0_FBDIV_SHIFT),
713 pll->reg_base + RK3399_PLLCON(0));
714
715 writel_relaxed(HIWORD_UPDATE(rate->refdiv, RK3399_PLLCON1_REFDIV_MASK,
716 RK3399_PLLCON1_REFDIV_SHIFT) |
717 HIWORD_UPDATE(rate->postdiv1, RK3399_PLLCON1_POSTDIV1_MASK,
718 RK3399_PLLCON1_POSTDIV1_SHIFT) |
719 HIWORD_UPDATE(rate->postdiv2, RK3399_PLLCON1_POSTDIV2_MASK,
720 RK3399_PLLCON1_POSTDIV2_SHIFT),
721 pll->reg_base + RK3399_PLLCON(1));
722
723 /* xPLL CON2 is not HIWORD_MASK */
724 pllcon = readl_relaxed(pll->reg_base + RK3399_PLLCON(2));
725 pllcon &= ~(RK3399_PLLCON2_FRAC_MASK << RK3399_PLLCON2_FRAC_SHIFT);
726 pllcon |= rate->frac << RK3399_PLLCON2_FRAC_SHIFT;
727 writel_relaxed(pllcon, pll->reg_base + RK3399_PLLCON(2));
728
729 writel_relaxed(HIWORD_UPDATE(rate->dsmpd, RK3399_PLLCON3_DSMPD_MASK,
730 RK3399_PLLCON3_DSMPD_SHIFT),
731 pll->reg_base + RK3399_PLLCON(3));
732
733 /* wait for the pll to lock */
734 ret = rockchip_rk3399_pll_wait_lock(pll);
735 if (ret) {
736 pr_warn("%s: pll update unsuccessful, trying to restore old params\n",
737 __func__);
738 rockchip_rk3399_pll_set_params(pll, &cur);
739 }
740
741 if (rate_change_remuxed)
742 pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM);
743
744 return ret;
745}
746
747static int rockchip_rk3399_pll_set_rate(struct clk_hw *hw, unsigned long drate,
748 unsigned long prate)
749{
750 struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
751 const struct rockchip_pll_rate_table *rate;
752 unsigned long old_rate = rockchip_rk3399_pll_recalc_rate(hw, prate);
753
754 pr_debug("%s: changing %s from %lu to %lu with a parent rate of %lu\n",
755 __func__, __clk_get_name(hw->clk), old_rate, drate, prate);
756
757 /* Get required rate settings from table */
758 rate = rockchip_get_pll_settings(pll, drate);
759 if (!rate) {
760 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
761 drate, __clk_get_name(hw->clk));
762 return -EINVAL;
763 }
764
765 return rockchip_rk3399_pll_set_params(pll, rate);
766}
767
768static int rockchip_rk3399_pll_enable(struct clk_hw *hw)
769{
770 struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
771
772 writel(HIWORD_UPDATE(0, RK3399_PLLCON3_PWRDOWN, 0),
773 pll->reg_base + RK3399_PLLCON(3));
774
775 return 0;
776}
777
778static void rockchip_rk3399_pll_disable(struct clk_hw *hw)
779{
780 struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
781
782 writel(HIWORD_UPDATE(RK3399_PLLCON3_PWRDOWN,
783 RK3399_PLLCON3_PWRDOWN, 0),
784 pll->reg_base + RK3399_PLLCON(3));
785}
786
787static int rockchip_rk3399_pll_is_enabled(struct clk_hw *hw)
788{
789 struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
790 u32 pllcon = readl(pll->reg_base + RK3399_PLLCON(3));
791
792 return !(pllcon & RK3399_PLLCON3_PWRDOWN);
793}
794
795static void rockchip_rk3399_pll_init(struct clk_hw *hw)
796{
797 struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
798 const struct rockchip_pll_rate_table *rate;
799 struct rockchip_pll_rate_table cur;
800 unsigned long drate;
801
802 if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE))
803 return;
804
805 drate = clk_hw_get_rate(hw);
806 rate = rockchip_get_pll_settings(pll, drate);
807
808 /* when no rate setting for the current rate, rely on clk_set_rate */
809 if (!rate)
810 return;
811
812 rockchip_rk3399_pll_get_params(pll, &cur);
813
814 pr_debug("%s: pll %s@%lu: Hz\n", __func__, __clk_get_name(hw->clk),
815 drate);
816 pr_debug("old - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
817 cur.fbdiv, cur.postdiv1, cur.refdiv, cur.postdiv2,
818 cur.dsmpd, cur.frac);
819 pr_debug("new - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
820 rate->fbdiv, rate->postdiv1, rate->refdiv, rate->postdiv2,
821 rate->dsmpd, rate->frac);
822
823 if (rate->fbdiv != cur.fbdiv || rate->postdiv1 != cur.postdiv1 ||
824 rate->refdiv != cur.refdiv || rate->postdiv2 != cur.postdiv2 ||
825 rate->dsmpd != cur.dsmpd || rate->frac != cur.frac) {
826 struct clk *parent = clk_get_parent(hw->clk);
827
828 if (!parent) {
829 pr_warn("%s: parent of %s not available\n",
830 __func__, __clk_get_name(hw->clk));
831 return;
832 }
833
834 pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n",
835 __func__, __clk_get_name(hw->clk));
836 rockchip_rk3399_pll_set_params(pll, rate);
837 }
838}
839
840static const struct clk_ops rockchip_rk3399_pll_clk_norate_ops = {
841 .recalc_rate = rockchip_rk3399_pll_recalc_rate,
842 .enable = rockchip_rk3399_pll_enable,
843 .disable = rockchip_rk3399_pll_disable,
844 .is_enabled = rockchip_rk3399_pll_is_enabled,
845};
846
847static const struct clk_ops rockchip_rk3399_pll_clk_ops = {
848 .recalc_rate = rockchip_rk3399_pll_recalc_rate,
849 .round_rate = rockchip_pll_round_rate,
850 .set_rate = rockchip_rk3399_pll_set_rate,
851 .enable = rockchip_rk3399_pll_enable,
852 .disable = rockchip_rk3399_pll_disable,
853 .is_enabled = rockchip_rk3399_pll_is_enabled,
854 .init = rockchip_rk3399_pll_init,
855};
856
596/* 857/*
597 * Common registering of pll clocks 858 * Common registering of pll clocks
598 */ 859 */
@@ -634,7 +895,9 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
634 pll_mux->lock = &ctx->lock; 895 pll_mux->lock = &ctx->lock;
635 pll_mux->hw.init = &init; 896 pll_mux->hw.init = &init;
636 897
637 if (pll_type == pll_rk3036 || pll_type == pll_rk3066) 898 if (pll_type == pll_rk3036 ||
899 pll_type == pll_rk3066 ||
900 pll_type == pll_rk3399)
638 pll_mux->flags |= CLK_MUX_HIWORD_MASK; 901 pll_mux->flags |= CLK_MUX_HIWORD_MASK;
639 902
640 /* the actual muxing is xin24m, pll-output, xin32k */ 903 /* the actual muxing is xin24m, pll-output, xin32k */
@@ -691,6 +954,12 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
691 else 954 else
692 init.ops = &rockchip_rk3066_pll_clk_ops; 955 init.ops = &rockchip_rk3066_pll_clk_ops;
693 break; 956 break;
957 case pll_rk3399:
958 if (!pll->rate_table)
959 init.ops = &rockchip_rk3399_pll_clk_norate_ops;
960 else
961 init.ops = &rockchip_rk3399_pll_clk_ops;
962 break;
694 default: 963 default:
695 pr_warn("%s: Unknown pll type for pll clk %s\n", 964 pr_warn("%s: Unknown pll type for pll clk %s\n",
696 __func__, name); 965 __func__, name);
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index e243d509da89..4798786703b8 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -96,6 +96,7 @@ struct clk;
96enum rockchip_pll_type { 96enum rockchip_pll_type {
97 pll_rk3036, 97 pll_rk3036,
98 pll_rk3066, 98 pll_rk3066,
99 pll_rk3399,
99}; 100};
100 101
101#define RK3036_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1, \ 102#define RK3036_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1, \
@@ -150,7 +151,7 @@ struct rockchip_pll_rate_table {
150 unsigned int nf; 151 unsigned int nf;
151 unsigned int no; 152 unsigned int no;
152 unsigned int nb; 153 unsigned int nb;
153 /* for RK3036 */ 154 /* for RK3036/RK3399 */
154 unsigned int fbdiv; 155 unsigned int fbdiv;
155 unsigned int postdiv1; 156 unsigned int postdiv1;
156 unsigned int refdiv; 157 unsigned int refdiv;