mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-30 18:05:48 +01:00 
			
		
		
		
	This function is a no-op. Remove it. Signed-off-by: Sean Anderson <seanga2@gmail.com> Link: https://lore.kernel.org/r/20231216193843.2463779-3-seanga2@gmail.com
		
			
				
	
	
		
			186 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			186 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0
 | |
| /*
 | |
|  * Xilinx 'Clocking Wizard' driver
 | |
|  *
 | |
|  * Copyright (c) 2021 Macronix Inc.
 | |
|  *
 | |
|  * Author: Zhengxun Li <zhengxunli@mxic.com.tw>
 | |
|  */
 | |
| 
 | |
| #include <common.h>
 | |
| #include <clk-uclass.h>
 | |
| #include <dm.h>
 | |
| #include <div64.h>
 | |
| #include <dm/device_compat.h>
 | |
| #include <linux/iopoll.h>
 | |
| 
 | |
| #include <linux/bitfield.h>
 | |
| 
 | |
| #define SRR			0x0
 | |
| 
 | |
| #define SR			0x4
 | |
| #define SR_LOCKED		BIT(0)
 | |
| 
 | |
| #define CCR(x)			(0x200 + ((x) * 4))
 | |
| 
 | |
| #define FBOUT_CFG		CCR(0)
 | |
| #define FBOUT_DIV(x)		(x)
 | |
| #define FBOUT_DIV_MASK		GENMASK(7, 0)
 | |
| #define FBOUT_GET_DIV(x)	FIELD_GET(FBOUT_DIV_MASK, x)
 | |
| #define FBOUT_MUL(x)		((x) << 8)
 | |
| #define FBOUT_MUL_MASK		GENMASK(15, 8)
 | |
| #define FBOUT_GET_MUL(x)	FIELD_GET(FBOUT_MUL_MASK, x)
 | |
| #define FBOUT_FRAC(x)		((x) << 16)
 | |
| #define FBOUT_FRAC_MASK		GENMASK(25, 16)
 | |
| #define FBOUT_GET_FRAC(x)	FIELD_GET(FBOUT_FRAC_MASK, x)
 | |
| #define FBOUT_FRAC_EN		BIT(26)
 | |
| 
 | |
| #define FBOUT_PHASE		CCR(1)
 | |
| 
 | |
| #define OUT_CFG(x)		CCR(2 + ((x) * 3))
 | |
| #define OUT_DIV(x)		(x)
 | |
| #define OUT_DIV_MASK		GENMASK(7, 0)
 | |
| #define OUT_GET_DIV(x)		FIELD_GET(OUT_DIV_MASK, x)
 | |
| #define OUT_FRAC(x)		((x) << 8)
 | |
| #define OUT_GET_MASK		GENMASK(17, 8)
 | |
| #define OUT_GET_FRAC(x)		FIELD_GET(OUT_GET_MASK, x)
 | |
| #define OUT_FRAC_EN		BIT(18)
 | |
| 
 | |
| #define OUT_PHASE(x)		CCR(3 + ((x) * 3))
 | |
| #define OUT_DUTY(x)		CCR(4 + ((x) * 3))
 | |
| 
 | |
| #define CTRL			CCR(23)
 | |
| #define CTRL_SEN		BIT(2)
 | |
| #define CTRL_SADDR		BIT(1)
 | |
| #define CTRL_LOAD		BIT(0)
 | |
| 
 | |
| /**
 | |
|  * struct clkwzrd - Clock wizard private data structure
 | |
|  *
 | |
|  * @base:		memory base
 | |
|  * @vco_clk:		voltage-controlled oscillator frequency
 | |
|  *
 | |
|  */
 | |
| struct clkwzd {
 | |
| 	void *base;
 | |
| 	u64 vco_clk;
 | |
| };
 | |
| 
 | |
| struct clkwzd_plat {
 | |
| 	fdt_addr_t addr;
 | |
| };
 | |
| 
 | |
| static int clk_wzrd_enable(struct clk *clk)
 | |
| {
 | |
| 	struct clkwzd *priv = dev_get_priv(clk->dev);
 | |
| 	int ret;
 | |
| 	u32 val;
 | |
| 
 | |
| 	ret = readl_poll_sleep_timeout(priv->base + SR, val, val & SR_LOCKED,
 | |
| 				       1, 100);
 | |
| 	if (!ret) {
 | |
| 		writel(CTRL_SEN | CTRL_SADDR | CTRL_LOAD, priv->base + CTRL);
 | |
| 		writel(CTRL_SADDR, priv->base + CTRL);
 | |
| 		ret = readl_poll_sleep_timeout(priv->base + SR, val,
 | |
| 					       val & SR_LOCKED, 1, 100);
 | |
| 	}
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| static unsigned long clk_wzrd_set_rate(struct clk *clk, ulong rate)
 | |
| {
 | |
| 	struct clkwzd *priv = dev_get_priv(clk->dev);
 | |
| 	u64 div;
 | |
| 	u32 cfg;
 | |
| 
 | |
| 	/* Get output clock divide value */
 | |
| 	div = DIV_ROUND_DOWN_ULL(priv->vco_clk * 1000, rate);
 | |
| 	if (div < 1000 || div > 255999)
 | |
| 		return -EINVAL;
 | |
| 
 | |
| 	cfg = OUT_DIV((u32)div / 1000);
 | |
| 
 | |
| 	writel(cfg, priv->base + OUT_CFG(clk->id));
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static struct clk_ops clk_wzrd_ops = {
 | |
| 	.enable = clk_wzrd_enable,
 | |
| 	.set_rate = clk_wzrd_set_rate,
 | |
| };
 | |
| 
 | |
| static int clk_wzrd_probe(struct udevice *dev)
 | |
| {
 | |
| 	struct clkwzd_plat *plat = dev_get_plat(dev);
 | |
| 	struct clkwzd *priv = dev_get_priv(dev);
 | |
| 	struct clk clk_in1;
 | |
| 	u64 clock, vco_clk;
 | |
| 	u32 cfg;
 | |
| 	int ret;
 | |
| 
 | |
| 	priv->base = (void *)plat->addr;
 | |
| 
 | |
| 	ret = clk_get_by_name(dev, "clk_in1", &clk_in1);
 | |
| 	if (ret < 0) {
 | |
| 		dev_err(dev, "failed to get clock\n");
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
| 	clock = clk_get_rate(&clk_in1);
 | |
| 	if (IS_ERR_VALUE(clock)) {
 | |
| 		dev_err(dev, "failed to get rate\n");
 | |
| 		return clock;
 | |
| 	}
 | |
| 
 | |
| 	ret = clk_enable(&clk_in1);
 | |
| 	if (ret) {
 | |
| 		dev_err(dev, "failed to enable clock\n");
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
| 	/* Read clock configuration registers */
 | |
| 	cfg = readl(priv->base + FBOUT_CFG);
 | |
| 
 | |
| 	/* Recalculate VCO rate */
 | |
| 	if (cfg & FBOUT_FRAC_EN)
 | |
| 		vco_clk = DIV_ROUND_DOWN_ULL(clock *
 | |
| 					     ((FBOUT_GET_MUL(cfg) * 1000) +
 | |
| 					      FBOUT_GET_FRAC(cfg)),
 | |
| 					     1000);
 | |
| 	else
 | |
| 		vco_clk = clock * FBOUT_GET_MUL(cfg);
 | |
| 
 | |
| 	priv->vco_clk = DIV_ROUND_DOWN_ULL(vco_clk, FBOUT_GET_DIV(cfg));
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int clk_wzrd_of_to_plat(struct udevice *dev)
 | |
| {
 | |
| 	struct clkwzd_plat *plat = dev_get_plat(dev);
 | |
| 
 | |
| 	plat->addr = dev_read_addr(dev);
 | |
| 	if (plat->addr == FDT_ADDR_T_NONE)
 | |
| 		return -EINVAL;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static const struct udevice_id clk_wzrd_ids[] = {
 | |
| 	{ .compatible = "xlnx,clocking-wizard" },
 | |
| 	{ /* sentinel */ }
 | |
| };
 | |
| 
 | |
| U_BOOT_DRIVER(clk_wzrd) = {
 | |
| 	.name = "zynq-clk-wizard",
 | |
| 	.id = UCLASS_CLK,
 | |
| 	.of_match = clk_wzrd_ids,
 | |
| 	.ops = &clk_wzrd_ops,
 | |
| 	.probe = clk_wzrd_probe,
 | |
| 	.of_to_plat = clk_wzrd_of_to_plat,
 | |
| 	.priv_auto = sizeof(struct clkwzd),
 | |
| 	.plat_auto = sizeof(struct clkwzd_plat),
 | |
| };
 |