Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: thead: support changing DPU pixel clock rate

The DPU pixel clock rate corresponds to the required dot clock of the
display mode, so it needs to be tweakable.

Add support to change it, by adding generic divider setting code,
arming the code to the dpu0/dpu1 clocks, and setting the pixel clock
connected to the DPU (after a gate) to CLK_SET_RATE_PARENT to propagate
it to the dividers.

Signed-off-by: Icenowy Zheng <uwu@icenowy.me>
Reviewed-by: Drew Fustini <fustini@kernel.org>
Signed-off-by: Drew Fustini <fustini@kernel.org>

authored by

Icenowy Zheng and committed by
Drew Fustini
8fede7ff 56a48c18

+58 -5
+58 -5
drivers/clk/thead/clk-th1520-ap.c
··· 56 56 57 57 struct ccu_div { 58 58 u32 enable; 59 + u32 div_en; 59 60 struct ccu_div_internal div; 60 61 struct ccu_internal mux; 61 62 struct ccu_common common; ··· 193 192 return rate; 194 193 } 195 194 195 + static int ccu_div_determine_rate(struct clk_hw *hw, 196 + struct clk_rate_request *req) 197 + { 198 + struct ccu_div *cd = hw_to_ccu_div(hw); 199 + unsigned int val; 200 + 201 + if (cd->div_en) 202 + return divider_determine_rate(hw, req, NULL, 203 + cd->div.width, cd->div.flags); 204 + 205 + regmap_read(cd->common.map, cd->common.cfg0, &val); 206 + val = val >> cd->div.shift; 207 + val &= GENMASK(cd->div.width - 1, 0); 208 + return divider_ro_determine_rate(hw, req, NULL, cd->div.width, 209 + cd->div.flags, val); 210 + } 211 + 212 + static int ccu_div_set_rate(struct clk_hw *hw, unsigned long rate, 213 + unsigned long parent_rate) 214 + { 215 + struct ccu_div *cd = hw_to_ccu_div(hw); 216 + int val = divider_get_val(rate, parent_rate, NULL, 217 + cd->div.width, cd->div.flags); 218 + unsigned int curr_val, reg_val; 219 + 220 + if (val < 0) 221 + return val; 222 + 223 + regmap_read(cd->common.map, cd->common.cfg0, &reg_val); 224 + curr_val = reg_val >> cd->div.shift; 225 + curr_val &= GENMASK(cd->div.width - 1, 0); 226 + 227 + if (!cd->div_en && curr_val != val) 228 + return -EINVAL; 229 + 230 + reg_val &= ~cd->div_en; 231 + regmap_write(cd->common.map, cd->common.cfg0, reg_val); 232 + udelay(1); 233 + 234 + reg_val &= ~GENMASK(cd->div.width + cd->div.shift - 1, cd->div.shift); 235 + reg_val |= val << cd->div.shift; 236 + regmap_write(cd->common.map, cd->common.cfg0, reg_val); 237 + 238 + reg_val |= cd->div_en; 239 + regmap_write(cd->common.map, cd->common.cfg0, reg_val); 240 + 241 + return 0; 242 + } 243 + 196 244 static u8 ccu_div_get_parent(struct clk_hw *hw) 197 245 { 198 246 struct ccu_div *cd = hw_to_ccu_div(hw); ··· 284 234 .get_parent = ccu_div_get_parent, 285 235 .set_parent = ccu_div_set_parent, 286 236 .recalc_rate = ccu_div_recalc_rate, 287 - .determine_rate = clk_hw_determine_rate_no_reparent, 237 + .set_rate = ccu_div_set_rate, 238 + .determine_rate = ccu_div_determine_rate, 288 239 }; 289 240 290 241 static void ccu_pll_disable(struct clk_hw *hw) ··· 829 778 }; 830 779 831 780 static struct ccu_div dpu0_clk = { 781 + .div_en = BIT(8), 832 782 .div = TH_CCU_DIV_FLAGS(0, 8, CLK_DIVIDER_ONE_BASED), 833 783 .common = { 834 784 .clkid = CLK_DPU0, ··· 837 785 .hw.init = CLK_HW_INIT_PARENTS_HW("dpu0", 838 786 dpu0_pll_clk_parent, 839 787 &ccu_div_ops, 840 - 0), 788 + CLK_SET_RATE_UNGATE), 841 789 }, 842 790 }; 843 791 ··· 846 794 }; 847 795 848 796 static struct ccu_div dpu1_clk = { 797 + .div_en = BIT(8), 849 798 .div = TH_CCU_DIV_FLAGS(0, 8, CLK_DIVIDER_ONE_BASED), 850 799 .common = { 851 800 .clkid = CLK_DPU1, ··· 854 801 .hw.init = CLK_HW_INIT_PARENTS_HW("dpu1", 855 802 dpu1_pll_clk_parent, 856 803 &ccu_div_ops, 857 - 0), 804 + CLK_SET_RATE_UNGATE), 858 805 }, 859 806 }; 860 807 ··· 942 889 static CCU_GATE(CLK_GPU_CFG_ACLK, gpu_cfg_aclk, "gpu-cfg-aclk", 943 890 video_pll_clk_pd, 0x0, 4, 0); 944 891 static CCU_GATE(CLK_DPU_PIXELCLK0, dpu0_pixelclk, "dpu0-pixelclk", 945 - dpu0_clk_pd, 0x0, 5, 0); 892 + dpu0_clk_pd, 0x0, 5, CLK_SET_RATE_PARENT); 946 893 static CCU_GATE(CLK_DPU_PIXELCLK1, dpu1_pixelclk, "dpu1-pixelclk", 947 - dpu1_clk_pd, 0x0, 6, 0); 894 + dpu1_clk_pd, 0x0, 6, CLK_SET_RATE_PARENT); 948 895 static CCU_GATE(CLK_DPU_HCLK, dpu_hclk, "dpu-hclk", video_pll_clk_pd, 0x0, 949 896 7, 0); 950 897 static CCU_GATE(CLK_DPU_ACLK, dpu_aclk, "dpu-aclk", video_pll_clk_pd, 0x0,