aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Boyd <sboyd@codeaurora.org>2015-11-30 20:31:41 -0500
committerStephen Boyd <sboyd@codeaurora.org>2015-11-30 21:24:29 -0500
commit55213e1acec9218580c90d36034aa0370a51daab (patch)
tree6666269d67fb2984891deecb65193508a513d920
parentb1e010c0730ab8861ef5a259ff5be7c78ccfb8ac (diff)
clk: qcom: Add gfx3d ping-pong PLL frequency switching
The GPU clocks on msm8996 have three dedicated PLLs, MMPLL2, MMPLL8, and MMPLL9. We leave MMPLL9 at the maximum speed (624 MHz), and we use MMPLL2 and MMPLL8 for the other frequencies. To make switching frequencies faster, we ping-pong between MMPLL2 and MMPLL8 when we're switching between frequencies that aren't the maximum. Implement custom rcg clk ops for this type of frequency switching. Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-rw-r--r--drivers/clk/qcom/clk-rcg.h1
-rw-r--r--drivers/clk/qcom/clk-rcg2.c87
2 files changed, 88 insertions, 0 deletions
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
index 4b1e94bdf29e..b904c335cda4 100644
--- a/drivers/clk/qcom/clk-rcg.h
+++ b/drivers/clk/qcom/clk-rcg.h
@@ -178,5 +178,6 @@ extern const struct clk_ops clk_edp_pixel_ops;
178extern const struct clk_ops clk_byte_ops; 178extern const struct clk_ops clk_byte_ops;
179extern const struct clk_ops clk_byte2_ops; 179extern const struct clk_ops clk_byte2_ops;
180extern const struct clk_ops clk_pixel_ops; 180extern const struct clk_ops clk_pixel_ops;
181extern const struct clk_ops clk_gfx3d_ops;
181 182
182#endif 183#endif
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index b544bb302f79..a071bba8018c 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -723,3 +723,90 @@ const struct clk_ops clk_pixel_ops = {
723 .determine_rate = clk_pixel_determine_rate, 723 .determine_rate = clk_pixel_determine_rate,
724}; 724};
725EXPORT_SYMBOL_GPL(clk_pixel_ops); 725EXPORT_SYMBOL_GPL(clk_pixel_ops);
726
727static int clk_gfx3d_determine_rate(struct clk_hw *hw,
728 struct clk_rate_request *req)
729{
730 struct clk_rate_request parent_req = { };
731 struct clk_hw *p2, *p8, *p9, *xo;
732 unsigned long p9_rate;
733 int ret;
734
735 xo = clk_hw_get_parent_by_index(hw, 0);
736 if (req->rate == clk_hw_get_rate(xo)) {
737 req->best_parent_hw = xo;
738 return 0;
739 }
740
741 p9 = clk_hw_get_parent_by_index(hw, 2);
742 p2 = clk_hw_get_parent_by_index(hw, 3);
743 p8 = clk_hw_get_parent_by_index(hw, 4);
744
745 /* PLL9 is a fixed rate PLL */
746 p9_rate = clk_hw_get_rate(p9);
747
748 parent_req.rate = req->rate = min(req->rate, p9_rate);
749 if (req->rate == p9_rate) {
750 req->rate = req->best_parent_rate = p9_rate;
751 req->best_parent_hw = p9;
752 return 0;
753 }
754
755 if (req->best_parent_hw == p9) {
756 /* Are we going back to a previously used rate? */
757 if (clk_hw_get_rate(p8) == req->rate)
758 req->best_parent_hw = p8;
759 else
760 req->best_parent_hw = p2;
761 } else if (req->best_parent_hw == p8) {
762 req->best_parent_hw = p2;
763 } else {
764 req->best_parent_hw = p8;
765 }
766
767 ret = __clk_determine_rate(req->best_parent_hw, &parent_req);
768 if (ret)
769 return ret;
770
771 req->rate = req->best_parent_rate = parent_req.rate;
772
773 return 0;
774}
775
776static int clk_gfx3d_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
777 unsigned long parent_rate, u8 index)
778{
779 struct clk_rcg2 *rcg = to_clk_rcg2(hw);
780 u32 cfg;
781 int ret;
782
783 /* Just mux it, we don't use the division or m/n hardware */
784 cfg = rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
785 ret = regmap_write(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, cfg);
786 if (ret)
787 return ret;
788
789 return update_config(rcg);
790}
791
792static int clk_gfx3d_set_rate(struct clk_hw *hw, unsigned long rate,
793 unsigned long parent_rate)
794{
795 /*
796 * We should never get here; clk_gfx3d_determine_rate() should always
797 * make us use a different parent than what we're currently using, so
798 * clk_gfx3d_set_rate_and_parent() should always be called.
799 */
800 return 0;
801}
802
803const struct clk_ops clk_gfx3d_ops = {
804 .is_enabled = clk_rcg2_is_enabled,
805 .get_parent = clk_rcg2_get_parent,
806 .set_parent = clk_rcg2_set_parent,
807 .recalc_rate = clk_rcg2_recalc_rate,
808 .set_rate = clk_gfx3d_set_rate,
809 .set_rate_and_parent = clk_gfx3d_set_rate_and_parent,
810 .determine_rate = clk_gfx3d_determine_rate,
811};
812EXPORT_SYMBOL_GPL(clk_gfx3d_ops);