Lines Matching +full:sync +full:- +full:freq

1 // SPDX-License-Identifier: GPL-2.0-only
3 // Copyright (C) 2020-2021 Samuel Holland <samuel@sholland.org>
25 #define MBUS_TMR_PERIOD(x) ((x) - 1)
28 #define MBUS_PMU_CFG_PERIOD(x) (((x) - 1) << 16)
108 return readl_relaxed(priv->reg_mbus + MBUS_TOTAL_BWCR); in sun8i_a33_mbus_get_peak_bw()
115 /* All PMU counters are cleared on a disable->enable transition. */ in sun8i_a33_mbus_restart_pmu_counters()
117 priv->reg_mbus + MBUS_PMU_CFG); in sun8i_a33_mbus_restart_pmu_counters()
119 priv->reg_mbus + MBUS_PMU_CFG); in sun8i_a33_mbus_restart_pmu_counters()
130 * ------------- * ------------ * -------- in sun8i_a33_mbus_update_nominal_bw()
133 priv->nominal_bw = ddr_freq_mhz * pmu_period * priv->data_width / 1024; in sun8i_a33_mbus_update_nominal_bw()
137 unsigned long freq) in sun8i_a33_mbus_set_dram_freq() argument
139 u32 ddr_freq_mhz = freq / USEC_PER_SEC; /* DDR */ in sun8i_a33_mbus_set_dram_freq()
147 ret = clk_set_rate(priv->clk_dram, freq); in sun8i_a33_mbus_set_dram_freq()
151 /* Disable automatic self-refesh and VTF before starting MDFS. */ in sun8i_a33_mbus_set_dram_freq()
152 pwrctl = readl_relaxed(priv->reg_dram + DRAM_PWRCTL) & in sun8i_a33_mbus_set_dram_freq()
154 writel_relaxed(pwrctl, priv->reg_dram + DRAM_PWRCTL); in sun8i_a33_mbus_set_dram_freq()
155 vtfcr = readl_relaxed(priv->reg_dram + DRAM_VTFCR); in sun8i_a33_mbus_set_dram_freq()
157 priv->reg_dram + DRAM_VTFCR); in sun8i_a33_mbus_set_dram_freq()
164 writel(mdfscr, priv->reg_mbus + MBUS_MDFSCR); in sun8i_a33_mbus_set_dram_freq()
167 tREFI_32ck = priv->tREFI_ns * mctl_freq_mhz / 1000 / 32; in sun8i_a33_mbus_set_dram_freq()
168 tRFC_ck = DIV_ROUND_UP(priv->tRFC_ns * mctl_freq_mhz, 1000); in sun8i_a33_mbus_set_dram_freq()
170 priv->reg_dram + DRAM_RFSHTMG); in sun8i_a33_mbus_set_dram_freq()
173 if (priv->odtmap && dram_freq_mhz > priv->variant->odt_freq_mhz) { in sun8i_a33_mbus_set_dram_freq()
175 writel(priv->odtmap, priv->reg_dram + DRAM_ODTMAP); in sun8i_a33_mbus_set_dram_freq()
178 writel(0, priv->reg_dram + DRAM_ODTMAP); in sun8i_a33_mbus_set_dram_freq()
181 void __iomem *reg = priv->reg_dram + DRAM_DXnGCR0(i); in sun8i_a33_mbus_set_dram_freq()
186 dev_dbg(priv->devfreq_dram->dev.parent, in sun8i_a33_mbus_set_dram_freq()
192 writel(mdfscr | MBUS_MDFSCR_START, priv->reg_mbus + MBUS_MDFSCR); in sun8i_a33_mbus_set_dram_freq()
193 ret = readl_poll_timeout_atomic(priv->reg_mbus + MBUS_MDFSCR, mdfscr, in sun8i_a33_mbus_set_dram_freq()
199 writel(0, priv->reg_mbus + MBUS_MDFSCR); in sun8i_a33_mbus_set_dram_freq()
202 writel_relaxed(vtfcr, priv->reg_dram + DRAM_VTFCR); in sun8i_a33_mbus_set_dram_freq()
204 /* Enable automatic self-refresh at the lowest frequency only. */ in sun8i_a33_mbus_set_dram_freq()
205 if (freq == priv->freq_table[0]) in sun8i_a33_mbus_set_dram_freq()
207 writel_relaxed(pwrctl, priv->reg_dram + DRAM_PWRCTL); in sun8i_a33_mbus_set_dram_freq()
216 unsigned long *freq, u32 flags) in sun8i_a33_mbus_set_dram_target() argument
219 struct devfreq *devfreq = priv->devfreq_dram; in sun8i_a33_mbus_set_dram_target()
223 opp = devfreq_recommended_opp(dev, freq, flags); in sun8i_a33_mbus_set_dram_target()
229 if (*freq == devfreq->previous_freq) in sun8i_a33_mbus_set_dram_target()
232 ret = sun8i_a33_mbus_set_dram_freq(priv, *freq); in sun8i_a33_mbus_set_dram_target()
235 *freq = devfreq->previous_freq; in sun8i_a33_mbus_set_dram_target()
246 stat->busy_time = sun8i_a33_mbus_get_peak_bw(priv); in sun8i_a33_mbus_get_dram_status()
247 stat->total_time = priv->nominal_bw; in sun8i_a33_mbus_get_dram_status()
248 stat->current_frequency = priv->devfreq_dram->previous_freq; in sun8i_a33_mbus_get_dram_status()
253 stat->busy_time, stat->total_time, in sun8i_a33_mbus_get_dram_status()
254 DIV_ROUND_CLOSEST(stat->busy_time * 100, stat->total_time), in sun8i_a33_mbus_get_dram_status()
255 stat->current_frequency / USEC_PER_SEC); in sun8i_a33_mbus_get_dram_status()
267 mbus_cr = readl_relaxed(priv->reg_mbus + MBUS_CR); in sun8i_a33_mbus_hw_init()
272 priv->tREFI_ns = 7800; in sun8i_a33_mbus_hw_init()
273 priv->tRFC_ns = 350; in sun8i_a33_mbus_hw_init()
277 priv->tREFI_ns = 3900; in sun8i_a33_mbus_hw_init()
278 priv->tRFC_ns = 210; in sun8i_a33_mbus_hw_init()
281 return -EINVAL; in sun8i_a33_mbus_hw_init()
285 priv->odtmap = readl_relaxed(priv->reg_dram + DRAM_ODTMAP); in sun8i_a33_mbus_hw_init()
289 void __iomem *reg = priv->reg_dram + DRAM_DXnGCR0(i); in sun8i_a33_mbus_hw_init()
294 priv->data_width = i; in sun8i_a33_mbus_hw_init()
296 dev_dbg(dev, "Detected %u-bit %sDDRx with%s ODT\n", in sun8i_a33_mbus_hw_init()
297 priv->data_width * 8, in sun8i_a33_mbus_hw_init()
299 priv->odtmap ? "" : "out"); in sun8i_a33_mbus_hw_init()
302 mbus_freq_mhz = clk_get_rate(priv->clk_mbus) / USEC_PER_SEC; in sun8i_a33_mbus_hw_init()
304 priv->reg_mbus + MBUS_TMR); in sun8i_a33_mbus_hw_init()
307 writel_relaxed(0xffffffff, priv->reg_mbus + MBUS_MDFSMRMR); in sun8i_a33_mbus_hw_init()
319 clk_disable_unprepare(priv->clk_bus); in sun8i_a33_mbus_suspend()
328 return clk_prepare_enable(priv->clk_bus); in sun8i_a33_mbus_resume()
334 struct device *dev = &pdev->dev; in sun8i_a33_mbus_probe()
343 return -EINVAL; in sun8i_a33_mbus_probe()
345 max_state = variant->max_dram_divider - variant->min_dram_divider + 1; in sun8i_a33_mbus_probe()
349 return -ENOMEM; in sun8i_a33_mbus_probe()
353 priv->variant = variant; in sun8i_a33_mbus_probe()
355 priv->reg_dram = devm_platform_ioremap_resource_byname(pdev, "dram"); in sun8i_a33_mbus_probe()
356 if (IS_ERR(priv->reg_dram)) in sun8i_a33_mbus_probe()
357 return PTR_ERR(priv->reg_dram); in sun8i_a33_mbus_probe()
359 priv->reg_mbus = devm_platform_ioremap_resource_byname(pdev, "mbus"); in sun8i_a33_mbus_probe()
360 if (IS_ERR(priv->reg_mbus)) in sun8i_a33_mbus_probe()
361 return PTR_ERR(priv->reg_mbus); in sun8i_a33_mbus_probe()
363 priv->clk_bus = devm_clk_get(dev, "bus"); in sun8i_a33_mbus_probe()
364 if (IS_ERR(priv->clk_bus)) in sun8i_a33_mbus_probe()
365 return dev_err_probe(dev, PTR_ERR(priv->clk_bus), in sun8i_a33_mbus_probe()
368 priv->clk_dram = devm_clk_get(dev, "dram"); in sun8i_a33_mbus_probe()
369 if (IS_ERR(priv->clk_dram)) in sun8i_a33_mbus_probe()
370 return dev_err_probe(dev, PTR_ERR(priv->clk_dram), in sun8i_a33_mbus_probe()
373 priv->clk_mbus = devm_clk_get(dev, "mbus"); in sun8i_a33_mbus_probe()
374 if (IS_ERR(priv->clk_mbus)) in sun8i_a33_mbus_probe()
375 return dev_err_probe(dev, PTR_ERR(priv->clk_mbus), in sun8i_a33_mbus_probe()
378 ret = clk_prepare_enable(priv->clk_bus); in sun8i_a33_mbus_probe()
383 /* Lock the DRAM clock rate to keep priv->nominal_bw in sync. */ in sun8i_a33_mbus_probe()
384 ret = clk_rate_exclusive_get(priv->clk_dram); in sun8i_a33_mbus_probe()
390 /* Lock the MBUS clock rate to keep MBUS_TMR_PERIOD in sync. */ in sun8i_a33_mbus_probe()
391 ret = clk_rate_exclusive_get(priv->clk_mbus); in sun8i_a33_mbus_probe()
397 priv->gov_data.upthreshold = 10; in sun8i_a33_mbus_probe()
398 priv->gov_data.downdifferential = 5; in sun8i_a33_mbus_probe()
400 priv->profile.initial_freq = clk_get_rate(priv->clk_dram); in sun8i_a33_mbus_probe()
401 priv->profile.polling_ms = 1000; in sun8i_a33_mbus_probe()
402 priv->profile.target = sun8i_a33_mbus_set_dram_target; in sun8i_a33_mbus_probe()
403 priv->profile.get_dev_status = sun8i_a33_mbus_get_dram_status; in sun8i_a33_mbus_probe()
404 priv->profile.freq_table = priv->freq_table; in sun8i_a33_mbus_probe()
405 priv->profile.max_state = max_state; in sun8i_a33_mbus_probe()
413 base_freq = clk_get_rate(clk_get_parent(priv->clk_dram)); in sun8i_a33_mbus_probe()
415 unsigned int div = variant->max_dram_divider - i; in sun8i_a33_mbus_probe()
417 priv->freq_table[i] = base_freq / div; in sun8i_a33_mbus_probe()
419 ret = dev_pm_opp_add(dev, priv->freq_table[i], 0); in sun8i_a33_mbus_probe()
426 ret = sun8i_a33_mbus_hw_init(dev, priv, priv->profile.initial_freq); in sun8i_a33_mbus_probe()
432 priv->devfreq_dram = devfreq_add_device(dev, &priv->profile, in sun8i_a33_mbus_probe()
434 &priv->gov_data); in sun8i_a33_mbus_probe()
435 if (IS_ERR(priv->devfreq_dram)) { in sun8i_a33_mbus_probe()
436 ret = PTR_ERR(priv->devfreq_dram); in sun8i_a33_mbus_probe()
445 priv->devfreq_dram->suspend_freq = priv->freq_table[0]; in sun8i_a33_mbus_probe()
452 clk_rate_exclusive_put(priv->clk_mbus); in sun8i_a33_mbus_probe()
454 clk_rate_exclusive_put(priv->clk_dram); in sun8i_a33_mbus_probe()
456 clk_disable_unprepare(priv->clk_bus); in sun8i_a33_mbus_probe()
464 unsigned long initial_freq = priv->profile.initial_freq; in sun8i_a33_mbus_remove()
465 struct device *dev = &pdev->dev; in sun8i_a33_mbus_remove()
468 devfreq_remove_device(priv->devfreq_dram); in sun8i_a33_mbus_remove()
475 clk_rate_exclusive_put(priv->clk_mbus); in sun8i_a33_mbus_remove()
476 clk_rate_exclusive_put(priv->clk_dram); in sun8i_a33_mbus_remove()
477 clk_disable_unprepare(priv->clk_bus); in sun8i_a33_mbus_remove()
489 { .compatible = "allwinner,sun50i-a64-mbus", .data = &sun50i_a64_mbus },
490 { .compatible = "allwinner,sun50i-h5-mbus", .data = &sun50i_a64_mbus },
502 .name = "sun8i-a33-mbus",