1 // SPDX-License-Identifier: BSD-3-Clause 2 /* 3 * Clock drivers for Qualcomm APQ8016, APQ8096 4 * 5 * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com> 6 * 7 * Based on Little Kernel driver, simplified 8 */ 9 10 #include <common.h> 11 #include <clk-uclass.h> 12 #include <dm.h> 13 #include <errno.h> 14 #include <asm/io.h> 15 #include <linux/bitops.h> 16 #include "clock-snapdragon.h" 17 18 /* CBCR register fields */ 19 #define CBCR_BRANCH_ENABLE_BIT BIT(0) 20 #define CBCR_BRANCH_OFF_BIT BIT(31) 21 22 extern ulong msm_set_rate(struct clk *clk, ulong rate); 23 24 /* Enable clock controlled by CBC soft macro */ 25 void clk_enable_cbc(phys_addr_t cbcr) 26 { 27 setbits_le32(cbcr, CBCR_BRANCH_ENABLE_BIT); 28 29 while (readl(cbcr) & CBCR_BRANCH_OFF_BIT) 30 ; 31 } 32 33 void clk_enable_gpll0(phys_addr_t base, const struct pll_vote_clk *gpll0) 34 { 35 if (readl(base + gpll0->status) & gpll0->status_bit) 36 return; /* clock already enabled */ 37 38 setbits_le32(base + gpll0->ena_vote, gpll0->vote_bit); 39 40 while ((readl(base + gpll0->status) & gpll0->status_bit) == 0) 41 ; 42 } 43 44 #define BRANCH_ON_VAL (0) 45 #define BRANCH_NOC_FSM_ON_VAL BIT(29) 46 #define BRANCH_CHECK_MASK GENMASK(31, 28) 47 48 void clk_enable_vote_clk(phys_addr_t base, const struct vote_clk *vclk) 49 { 50 u32 val; 51 52 setbits_le32(base + vclk->ena_vote, vclk->vote_bit); 53 do { 54 val = readl(base + vclk->cbcr_reg); 55 val &= BRANCH_CHECK_MASK; 56 } while ((val != BRANCH_ON_VAL) && (val != BRANCH_NOC_FSM_ON_VAL)); 57 } 58 59 #define APPS_CMD_RGCR_UPDATE BIT(0) 60 61 /* Update clock command via CMD_RGCR */ 62 void clk_bcr_update(phys_addr_t apps_cmd_rgcr) 63 { 64 setbits_le32(apps_cmd_rgcr, APPS_CMD_RGCR_UPDATE); 65 66 /* Wait for frequency to be updated. */ 67 while (readl(apps_cmd_rgcr) & APPS_CMD_RGCR_UPDATE) 68 ; 69 } 70 71 #define CFG_MODE_DUAL_EDGE (0x2 << 12) /* Counter mode */ 72 73 #define CFG_MASK 0x3FFF 74 75 #define CFG_DIVIDER_MASK 0x1F 76 77 /* root set rate for clocks with half integer and MND divider */ 78 void clk_rcg_set_rate_mnd(phys_addr_t base, const struct bcr_regs *regs, 79 int div, int m, int n, int source) 80 { 81 u32 cfg; 82 /* M value for MND divider. */ 83 u32 m_val = m; 84 /* NOT(N-M) value for MND divider. */ 85 u32 n_val = ~((n) - (m)) * !!(n); 86 /* NOT 2D value for MND divider. */ 87 u32 d_val = ~(n); 88 89 /* Program MND values */ 90 writel(m_val, base + regs->M); 91 writel(n_val, base + regs->N); 92 writel(d_val, base + regs->D); 93 94 /* setup src select and divider */ 95 cfg = readl(base + regs->cfg_rcgr); 96 cfg &= ~CFG_MASK; 97 cfg |= source & CFG_CLK_SRC_MASK; /* Select clock source */ 98 99 /* Set the divider; HW permits fraction dividers (+0.5), but 100 for simplicity, we will support integers only */ 101 if (div) 102 cfg |= (2 * div - 1) & CFG_DIVIDER_MASK; 103 104 if (n_val) 105 cfg |= CFG_MODE_DUAL_EDGE; 106 107 writel(cfg, base + regs->cfg_rcgr); /* Write new clock configuration */ 108 109 /* Inform h/w to start using the new config. */ 110 clk_bcr_update(base + regs->cmd_rcgr); 111 } 112 113 static int msm_clk_probe(struct udevice *dev) 114 { 115 struct msm_clk_priv *priv = dev_get_priv(dev); 116 117 priv->base = devfdt_get_addr(dev); 118 if (priv->base == FDT_ADDR_T_NONE) 119 return -EINVAL; 120 121 return 0; 122 } 123 124 static ulong msm_clk_set_rate(struct clk *clk, ulong rate) 125 { 126 return msm_set_rate(clk, rate); 127 } 128 129 static struct clk_ops msm_clk_ops = { 130 .set_rate = msm_clk_set_rate, 131 }; 132 133 static const struct udevice_id msm_clk_ids[] = { 134 { .compatible = "qcom,gcc-msm8916" }, 135 { .compatible = "qcom,gcc-apq8016" }, 136 { .compatible = "qcom,gcc-msm8996" }, 137 { .compatible = "qcom,gcc-apq8096" }, 138 { } 139 }; 140 141 U_BOOT_DRIVER(clk_msm) = { 142 .name = "clk_msm", 143 .id = UCLASS_CLK, 144 .of_match = msm_clk_ids, 145 .ops = &msm_clk_ops, 146 .priv_auto_alloc_size = sizeof(struct msm_clk_priv), 147 .probe = msm_clk_probe, 148 }; 149