1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/clk-provider.h> 3 #include <linux/io.h> 4 #include <linux/regulator/consumer.h> 5 6 #include "mcde_drm.h" 7 #include "mcde_display_regs.h" 8 9 /* The MCDE internal clock dividers for FIFO A and B */ 10 struct mcde_clk_div { 11 struct clk_hw hw; 12 struct mcde *mcde; 13 u32 cr; 14 u32 cr_div; 15 }; 16 17 static int mcde_clk_div_enable(struct clk_hw *hw) 18 { 19 struct mcde_clk_div *cdiv = container_of(hw, struct mcde_clk_div, hw); 20 struct mcde *mcde = cdiv->mcde; 21 u32 val; 22 23 spin_lock(&mcde->fifo_crx1_lock); 24 val = readl(mcde->regs + cdiv->cr); 25 /* 26 * Select the PLL72 (LCD) clock as parent 27 * FIXME: implement other parents. 28 */ 29 val &= ~MCDE_CRX1_CLKSEL_MASK; 30 val |= MCDE_CRX1_CLKSEL_CLKPLL72 << MCDE_CRX1_CLKSEL_SHIFT; 31 /* Internal clock */ 32 val |= MCDE_CRA1_CLKTYPE_TVXCLKSEL1; 33 34 /* Clear then set the divider */ 35 val &= ~(MCDE_CRX1_BCD | MCDE_CRX1_PCD_MASK); 36 val |= cdiv->cr_div; 37 38 writel(val, mcde->regs + cdiv->cr); 39 spin_unlock(&mcde->fifo_crx1_lock); 40 41 return 0; 42 } 43 44 static int mcde_clk_div_choose_div(struct clk_hw *hw, unsigned long rate, 45 unsigned long *prate, bool set_parent) 46 { 47 int best_div = 1, div; 48 struct clk_hw *parent = clk_hw_get_parent(hw); 49 unsigned long best_prate = 0; 50 unsigned long best_diff = ~0ul; 51 int max_div = (1 << MCDE_CRX1_PCD_BITS) - 1; 52 53 for (div = 1; div < max_div; div++) { 54 unsigned long this_prate, div_rate, diff; 55 56 if (set_parent) 57 this_prate = clk_hw_round_rate(parent, rate * div); 58 else 59 this_prate = *prate; 60 div_rate = DIV_ROUND_UP_ULL(this_prate, div); 61 diff = abs(rate - div_rate); 62 63 if (diff < best_diff) { 64 best_div = div; 65 best_diff = diff; 66 best_prate = this_prate; 67 } 68 } 69 70 *prate = best_prate; 71 return best_div; 72 } 73 74 static long mcde_clk_div_round_rate(struct clk_hw *hw, unsigned long rate, 75 unsigned long *prate) 76 { 77 int div = mcde_clk_div_choose_div(hw, rate, prate, true); 78 79 return DIV_ROUND_UP_ULL(*prate, div); 80 } 81 82 static unsigned long mcde_clk_div_recalc_rate(struct clk_hw *hw, 83 unsigned long prate) 84 { 85 struct mcde_clk_div *cdiv = container_of(hw, struct mcde_clk_div, hw); 86 struct mcde *mcde = cdiv->mcde; 87 u32 cr; 88 int div; 89 90 /* 91 * If the MCDE is not powered we can't access registers. 92 * It will come up with 0 in the divider register bits, which 93 * means "divide by 2". 94 */ 95 if (!regulator_is_enabled(mcde->epod)) 96 return DIV_ROUND_UP_ULL(prate, 2); 97 98 cr = readl(mcde->regs + cdiv->cr); 99 if (cr & MCDE_CRX1_BCD) 100 return prate; 101 102 /* 0 in the PCD means "divide by 2", 1 means "divide by 3" etc */ 103 div = cr & MCDE_CRX1_PCD_MASK; 104 div += 2; 105 106 return DIV_ROUND_UP_ULL(prate, div); 107 } 108 109 static int mcde_clk_div_set_rate(struct clk_hw *hw, unsigned long rate, 110 unsigned long prate) 111 { 112 struct mcde_clk_div *cdiv = container_of(hw, struct mcde_clk_div, hw); 113 int div = mcde_clk_div_choose_div(hw, rate, &prate, false); 114 u32 cr = 0; 115 116 /* 117 * We cache the CR bits to set the divide in the state so that 118 * we can call this before we can even write to the hardware. 119 */ 120 if (div == 1) { 121 /* Bypass clock divider */ 122 cr |= MCDE_CRX1_BCD; 123 } else { 124 div -= 2; 125 cr |= div & MCDE_CRX1_PCD_MASK; 126 } 127 cdiv->cr_div = cr; 128 129 return 0; 130 } 131 132 static const struct clk_ops mcde_clk_div_ops = { 133 .enable = mcde_clk_div_enable, 134 .recalc_rate = mcde_clk_div_recalc_rate, 135 .round_rate = mcde_clk_div_round_rate, 136 .set_rate = mcde_clk_div_set_rate, 137 }; 138 139 int mcde_init_clock_divider(struct mcde *mcde) 140 { 141 struct device *dev = mcde->dev; 142 struct mcde_clk_div *fifoa; 143 struct mcde_clk_div *fifob; 144 const char *parent_name; 145 struct clk_init_data fifoa_init = { 146 .name = "fifoa", 147 .ops = &mcde_clk_div_ops, 148 .parent_names = &parent_name, 149 .num_parents = 1, 150 .flags = CLK_SET_RATE_PARENT, 151 }; 152 struct clk_init_data fifob_init = { 153 .name = "fifob", 154 .ops = &mcde_clk_div_ops, 155 .parent_names = &parent_name, 156 .num_parents = 1, 157 .flags = CLK_SET_RATE_PARENT, 158 }; 159 int ret; 160 161 spin_lock_init(&mcde->fifo_crx1_lock); 162 parent_name = __clk_get_name(mcde->lcd_clk); 163 164 /* Allocate 2 clocks */ 165 fifoa = devm_kzalloc(dev, sizeof(*fifoa), GFP_KERNEL); 166 if (!fifoa) 167 return -ENOMEM; 168 fifob = devm_kzalloc(dev, sizeof(*fifob), GFP_KERNEL); 169 if (!fifob) 170 return -ENOMEM; 171 172 fifoa->mcde = mcde; 173 fifoa->cr = MCDE_CRA1; 174 fifoa->hw.init = &fifoa_init; 175 ret = devm_clk_hw_register(dev, &fifoa->hw); 176 if (ret) { 177 dev_err(dev, "error registering FIFO A clock divider\n"); 178 return ret; 179 } 180 mcde->fifoa_clk = fifoa->hw.clk; 181 182 fifob->mcde = mcde; 183 fifob->cr = MCDE_CRB1; 184 fifob->hw.init = &fifob_init; 185 ret = devm_clk_hw_register(dev, &fifob->hw); 186 if (ret) { 187 dev_err(dev, "error registering FIFO B clock divider\n"); 188 return ret; 189 } 190 mcde->fifob_clk = fifob->hw.clk; 191 192 return 0; 193 } 194