cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

clk-xgene.c (19177B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * clk-xgene.c - AppliedMicro X-Gene Clock Interface
      4 *
      5 * Copyright (c) 2013, Applied Micro Circuits Corporation
      6 * Author: Loc Ho <lho@apm.com>
      7 */
      8#include <linux/module.h>
      9#include <linux/spinlock.h>
     10#include <linux/io.h>
     11#include <linux/of.h>
     12#include <linux/clkdev.h>
     13#include <linux/clk-provider.h>
     14#include <linux/of_address.h>
     15
     16/* Register SCU_PCPPLL bit fields */
     17#define N_DIV_RD(src)			((src) & 0x000001ff)
     18#define SC_N_DIV_RD(src)		((src) & 0x0000007f)
     19#define SC_OUTDIV2(src)			(((src) & 0x00000100) >> 8)
     20
     21/* Register SCU_SOCPLL bit fields */
     22#define CLKR_RD(src)			(((src) & 0x07000000)>>24)
     23#define CLKOD_RD(src)			(((src) & 0x00300000)>>20)
     24#define REGSPEC_RESET_F1_MASK		0x00010000
     25#define CLKF_RD(src)			(((src) & 0x000001ff))
     26
     27#define XGENE_CLK_DRIVER_VER		"0.1"
     28
     29static DEFINE_SPINLOCK(clk_lock);
     30
     31static inline u32 xgene_clk_read(void __iomem *csr)
     32{
     33	return readl_relaxed(csr);
     34}
     35
     36static inline void xgene_clk_write(u32 data, void __iomem *csr)
     37{
     38	writel_relaxed(data, csr);
     39}
     40
     41/* PLL Clock */
     42enum xgene_pll_type {
     43	PLL_TYPE_PCP = 0,
     44	PLL_TYPE_SOC = 1,
     45};
     46
     47struct xgene_clk_pll {
     48	struct clk_hw	hw;
     49	void __iomem	*reg;
     50	spinlock_t	*lock;
     51	u32		pll_offset;
     52	enum xgene_pll_type	type;
     53	int		version;
     54};
     55
     56#define to_xgene_clk_pll(_hw) container_of(_hw, struct xgene_clk_pll, hw)
     57
     58static int xgene_clk_pll_is_enabled(struct clk_hw *hw)
     59{
     60	struct xgene_clk_pll *pllclk = to_xgene_clk_pll(hw);
     61	u32 data;
     62
     63	data = xgene_clk_read(pllclk->reg + pllclk->pll_offset);
     64	pr_debug("%s pll %s\n", clk_hw_get_name(hw),
     65		data & REGSPEC_RESET_F1_MASK ? "disabled" : "enabled");
     66
     67	return data & REGSPEC_RESET_F1_MASK ? 0 : 1;
     68}
     69
     70static unsigned long xgene_clk_pll_recalc_rate(struct clk_hw *hw,
     71				unsigned long parent_rate)
     72{
     73	struct xgene_clk_pll *pllclk = to_xgene_clk_pll(hw);
     74	unsigned long fref;
     75	unsigned long fvco;
     76	u32 pll;
     77	u32 nref;
     78	u32 nout;
     79	u32 nfb;
     80
     81	pll = xgene_clk_read(pllclk->reg + pllclk->pll_offset);
     82
     83	if (pllclk->version <= 1) {
     84		if (pllclk->type == PLL_TYPE_PCP) {
     85			/*
     86			* PLL VCO = Reference clock * NF
     87			* PCP PLL = PLL_VCO / 2
     88			*/
     89			nout = 2;
     90			fvco = parent_rate * (N_DIV_RD(pll) + 4);
     91		} else {
     92			/*
     93			* Fref = Reference Clock / NREF;
     94			* Fvco = Fref * NFB;
     95			* Fout = Fvco / NOUT;
     96			*/
     97			nref = CLKR_RD(pll) + 1;
     98			nout = CLKOD_RD(pll) + 1;
     99			nfb = CLKF_RD(pll);
    100			fref = parent_rate / nref;
    101			fvco = fref * nfb;
    102		}
    103	} else {
    104		/*
    105		 * fvco = Reference clock * FBDIVC
    106		 * PLL freq = fvco / NOUT
    107		 */
    108		nout = SC_OUTDIV2(pll) ? 2 : 3;
    109		fvco = parent_rate * SC_N_DIV_RD(pll);
    110	}
    111	pr_debug("%s pll recalc rate %ld parent %ld version %d\n",
    112		 clk_hw_get_name(hw), fvco / nout, parent_rate,
    113		 pllclk->version);
    114
    115	return fvco / nout;
    116}
    117
    118static const struct clk_ops xgene_clk_pll_ops = {
    119	.is_enabled = xgene_clk_pll_is_enabled,
    120	.recalc_rate = xgene_clk_pll_recalc_rate,
    121};
    122
    123static struct clk *xgene_register_clk_pll(struct device *dev,
    124	const char *name, const char *parent_name,
    125	unsigned long flags, void __iomem *reg, u32 pll_offset,
    126	u32 type, spinlock_t *lock, int version)
    127{
    128	struct xgene_clk_pll *apmclk;
    129	struct clk *clk;
    130	struct clk_init_data init;
    131
    132	/* allocate the APM clock structure */
    133	apmclk = kzalloc(sizeof(*apmclk), GFP_KERNEL);
    134	if (!apmclk)
    135		return ERR_PTR(-ENOMEM);
    136
    137	init.name = name;
    138	init.ops = &xgene_clk_pll_ops;
    139	init.flags = flags;
    140	init.parent_names = parent_name ? &parent_name : NULL;
    141	init.num_parents = parent_name ? 1 : 0;
    142
    143	apmclk->version = version;
    144	apmclk->reg = reg;
    145	apmclk->lock = lock;
    146	apmclk->pll_offset = pll_offset;
    147	apmclk->type = type;
    148	apmclk->hw.init = &init;
    149
    150	/* Register the clock */
    151	clk = clk_register(dev, &apmclk->hw);
    152	if (IS_ERR(clk)) {
    153		pr_err("%s: could not register clk %s\n", __func__, name);
    154		kfree(apmclk);
    155		return NULL;
    156	}
    157	return clk;
    158}
    159
    160static int xgene_pllclk_version(struct device_node *np)
    161{
    162	if (of_device_is_compatible(np, "apm,xgene-socpll-clock"))
    163		return 1;
    164	if (of_device_is_compatible(np, "apm,xgene-pcppll-clock"))
    165		return 1;
    166	return 2;
    167}
    168
    169static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_type)
    170{
    171	const char *clk_name = np->full_name;
    172	struct clk *clk;
    173	void __iomem *reg;
    174	int version = xgene_pllclk_version(np);
    175
    176	reg = of_iomap(np, 0);
    177	if (!reg) {
    178		pr_err("Unable to map CSR register for %pOF\n", np);
    179		return;
    180	}
    181	of_property_read_string(np, "clock-output-names", &clk_name);
    182	clk = xgene_register_clk_pll(NULL,
    183			clk_name, of_clk_get_parent_name(np, 0),
    184			0, reg, 0, pll_type, &clk_lock,
    185			version);
    186	if (!IS_ERR(clk)) {
    187		of_clk_add_provider(np, of_clk_src_simple_get, clk);
    188		clk_register_clkdev(clk, clk_name, NULL);
    189		pr_debug("Add %s clock PLL\n", clk_name);
    190	}
    191}
    192
    193static void xgene_socpllclk_init(struct device_node *np)
    194{
    195	xgene_pllclk_init(np, PLL_TYPE_SOC);
    196}
    197
    198static void xgene_pcppllclk_init(struct device_node *np)
    199{
    200	xgene_pllclk_init(np, PLL_TYPE_PCP);
    201}
    202
    203/**
    204 * struct xgene_clk_pmd - PMD clock
    205 *
    206 * @hw:		handle between common and hardware-specific interfaces
    207 * @reg:	register containing the fractional scale multiplier (scaler)
    208 * @shift:	shift to the unit bit field
    209 * @mask:	mask to the unit bit field
    210 * @denom:	1/denominator unit
    211 * @lock:	register lock
    212 * @flags: XGENE_CLK_PMD_SCALE_INVERTED - By default the scaler is the value read
    213 *	from the register plus one. For example,
    214 *		0 for (0 + 1) / denom,
    215 *		1 for (1 + 1) / denom and etc.
    216 *	If this flag is set, it is
    217 *		0 for (denom - 0) / denom,
    218 *		1 for (denom - 1) / denom and etc.
    219 */
    220struct xgene_clk_pmd {
    221	struct clk_hw	hw;
    222	void __iomem	*reg;
    223	u8		shift;
    224	u32		mask;
    225	u64		denom;
    226	u32		flags;
    227	spinlock_t	*lock;
    228};
    229
    230#define to_xgene_clk_pmd(_hw) container_of(_hw, struct xgene_clk_pmd, hw)
    231
    232#define XGENE_CLK_PMD_SCALE_INVERTED	BIT(0)
    233#define XGENE_CLK_PMD_SHIFT		8
    234#define XGENE_CLK_PMD_WIDTH		3
    235
    236static unsigned long xgene_clk_pmd_recalc_rate(struct clk_hw *hw,
    237					       unsigned long parent_rate)
    238{
    239	struct xgene_clk_pmd *fd = to_xgene_clk_pmd(hw);
    240	unsigned long flags = 0;
    241	u64 ret, scale;
    242	u32 val;
    243
    244	if (fd->lock)
    245		spin_lock_irqsave(fd->lock, flags);
    246	else
    247		__acquire(fd->lock);
    248
    249	val = readl(fd->reg);
    250
    251	if (fd->lock)
    252		spin_unlock_irqrestore(fd->lock, flags);
    253	else
    254		__release(fd->lock);
    255
    256	ret = (u64)parent_rate;
    257
    258	scale = (val & fd->mask) >> fd->shift;
    259	if (fd->flags & XGENE_CLK_PMD_SCALE_INVERTED)
    260		scale = fd->denom - scale;
    261	else
    262		scale++;
    263
    264	/* freq = parent_rate * scaler / denom */
    265	do_div(ret, fd->denom);
    266	ret *= scale;
    267	if (ret == 0)
    268		ret = (u64)parent_rate;
    269
    270	return ret;
    271}
    272
    273static long xgene_clk_pmd_round_rate(struct clk_hw *hw, unsigned long rate,
    274				     unsigned long *parent_rate)
    275{
    276	struct xgene_clk_pmd *fd = to_xgene_clk_pmd(hw);
    277	u64 ret, scale;
    278
    279	if (!rate || rate >= *parent_rate)
    280		return *parent_rate;
    281
    282	/* freq = parent_rate * scaler / denom */
    283	ret = rate * fd->denom;
    284	scale = DIV_ROUND_UP_ULL(ret, *parent_rate);
    285
    286	ret = (u64)*parent_rate * scale;
    287	do_div(ret, fd->denom);
    288
    289	return ret;
    290}
    291
    292static int xgene_clk_pmd_set_rate(struct clk_hw *hw, unsigned long rate,
    293				  unsigned long parent_rate)
    294{
    295	struct xgene_clk_pmd *fd = to_xgene_clk_pmd(hw);
    296	unsigned long flags = 0;
    297	u64 scale, ret;
    298	u32 val;
    299
    300	/*
    301	 * Compute the scaler:
    302	 *
    303	 * freq = parent_rate * scaler / denom, or
    304	 * scaler = freq * denom / parent_rate
    305	 */
    306	ret = rate * fd->denom;
    307	scale = DIV_ROUND_UP_ULL(ret, (u64)parent_rate);
    308
    309	/* Check if inverted */
    310	if (fd->flags & XGENE_CLK_PMD_SCALE_INVERTED)
    311		scale = fd->denom - scale;
    312	else
    313		scale--;
    314
    315	if (fd->lock)
    316		spin_lock_irqsave(fd->lock, flags);
    317	else
    318		__acquire(fd->lock);
    319
    320	val = readl(fd->reg);
    321	val &= ~fd->mask;
    322	val |= (scale << fd->shift);
    323	writel(val, fd->reg);
    324
    325	if (fd->lock)
    326		spin_unlock_irqrestore(fd->lock, flags);
    327	else
    328		__release(fd->lock);
    329
    330	return 0;
    331}
    332
    333static const struct clk_ops xgene_clk_pmd_ops = {
    334	.recalc_rate = xgene_clk_pmd_recalc_rate,
    335	.round_rate = xgene_clk_pmd_round_rate,
    336	.set_rate = xgene_clk_pmd_set_rate,
    337};
    338
    339static struct clk *
    340xgene_register_clk_pmd(struct device *dev,
    341		       const char *name, const char *parent_name,
    342		       unsigned long flags, void __iomem *reg, u8 shift,
    343		       u8 width, u64 denom, u32 clk_flags, spinlock_t *lock)
    344{
    345	struct xgene_clk_pmd *fd;
    346	struct clk_init_data init;
    347	struct clk *clk;
    348
    349	fd = kzalloc(sizeof(*fd), GFP_KERNEL);
    350	if (!fd)
    351		return ERR_PTR(-ENOMEM);
    352
    353	init.name = name;
    354	init.ops = &xgene_clk_pmd_ops;
    355	init.flags = flags;
    356	init.parent_names = parent_name ? &parent_name : NULL;
    357	init.num_parents = parent_name ? 1 : 0;
    358
    359	fd->reg = reg;
    360	fd->shift = shift;
    361	fd->mask = (BIT(width) - 1) << shift;
    362	fd->denom = denom;
    363	fd->flags = clk_flags;
    364	fd->lock = lock;
    365	fd->hw.init = &init;
    366
    367	clk = clk_register(dev, &fd->hw);
    368	if (IS_ERR(clk)) {
    369		pr_err("%s: could not register clk %s\n", __func__, name);
    370		kfree(fd);
    371		return NULL;
    372	}
    373
    374	return clk;
    375}
    376
    377static void xgene_pmdclk_init(struct device_node *np)
    378{
    379	const char *clk_name = np->full_name;
    380	void __iomem *csr_reg;
    381	struct resource res;
    382	struct clk *clk;
    383	u64 denom;
    384	u32 flags = 0;
    385	int rc;
    386
    387	/* Check if the entry is disabled */
    388	if (!of_device_is_available(np))
    389		return;
    390
    391	/* Parse the DTS register for resource */
    392	rc = of_address_to_resource(np, 0, &res);
    393	if (rc != 0) {
    394		pr_err("no DTS register for %pOF\n", np);
    395		return;
    396	}
    397	csr_reg = of_iomap(np, 0);
    398	if (!csr_reg) {
    399		pr_err("Unable to map resource for %pOF\n", np);
    400		return;
    401	}
    402	of_property_read_string(np, "clock-output-names", &clk_name);
    403
    404	denom = BIT(XGENE_CLK_PMD_WIDTH);
    405	flags |= XGENE_CLK_PMD_SCALE_INVERTED;
    406
    407	clk = xgene_register_clk_pmd(NULL, clk_name,
    408				     of_clk_get_parent_name(np, 0), 0,
    409				     csr_reg, XGENE_CLK_PMD_SHIFT,
    410				     XGENE_CLK_PMD_WIDTH, denom,
    411				     flags, &clk_lock);
    412	if (!IS_ERR(clk)) {
    413		of_clk_add_provider(np, of_clk_src_simple_get, clk);
    414		clk_register_clkdev(clk, clk_name, NULL);
    415		pr_debug("Add %s clock\n", clk_name);
    416	} else {
    417		if (csr_reg)
    418			iounmap(csr_reg);
    419	}
    420}
    421
    422/* IP Clock */
    423struct xgene_dev_parameters {
    424	void __iomem *csr_reg;		/* CSR for IP clock */
    425	u32 reg_clk_offset;		/* Offset to clock enable CSR */
    426	u32 reg_clk_mask;		/* Mask bit for clock enable */
    427	u32 reg_csr_offset;		/* Offset to CSR reset */
    428	u32 reg_csr_mask;		/* Mask bit for disable CSR reset */
    429	void __iomem *divider_reg;	/* CSR for divider */
    430	u32 reg_divider_offset;		/* Offset to divider register */
    431	u32 reg_divider_shift;		/* Bit shift to divider field */
    432	u32 reg_divider_width;		/* Width of the bit to divider field */
    433};
    434
    435struct xgene_clk {
    436	struct clk_hw	hw;
    437	spinlock_t	*lock;
    438	struct xgene_dev_parameters	param;
    439};
    440
    441#define to_xgene_clk(_hw) container_of(_hw, struct xgene_clk, hw)
    442
    443static int xgene_clk_enable(struct clk_hw *hw)
    444{
    445	struct xgene_clk *pclk = to_xgene_clk(hw);
    446	unsigned long flags = 0;
    447	u32 data;
    448
    449	if (pclk->lock)
    450		spin_lock_irqsave(pclk->lock, flags);
    451
    452	if (pclk->param.csr_reg) {
    453		pr_debug("%s clock enabled\n", clk_hw_get_name(hw));
    454		/* First enable the clock */
    455		data = xgene_clk_read(pclk->param.csr_reg +
    456					pclk->param.reg_clk_offset);
    457		data |= pclk->param.reg_clk_mask;
    458		xgene_clk_write(data, pclk->param.csr_reg +
    459					pclk->param.reg_clk_offset);
    460		pr_debug("%s clk offset 0x%08X mask 0x%08X value 0x%08X\n",
    461			clk_hw_get_name(hw),
    462			pclk->param.reg_clk_offset, pclk->param.reg_clk_mask,
    463			data);
    464
    465		/* Second enable the CSR */
    466		data = xgene_clk_read(pclk->param.csr_reg +
    467					pclk->param.reg_csr_offset);
    468		data &= ~pclk->param.reg_csr_mask;
    469		xgene_clk_write(data, pclk->param.csr_reg +
    470					pclk->param.reg_csr_offset);
    471		pr_debug("%s csr offset 0x%08X mask 0x%08X value 0x%08X\n",
    472			clk_hw_get_name(hw),
    473			pclk->param.reg_csr_offset, pclk->param.reg_csr_mask,
    474			data);
    475	}
    476
    477	if (pclk->lock)
    478		spin_unlock_irqrestore(pclk->lock, flags);
    479
    480	return 0;
    481}
    482
    483static void xgene_clk_disable(struct clk_hw *hw)
    484{
    485	struct xgene_clk *pclk = to_xgene_clk(hw);
    486	unsigned long flags = 0;
    487	u32 data;
    488
    489	if (pclk->lock)
    490		spin_lock_irqsave(pclk->lock, flags);
    491
    492	if (pclk->param.csr_reg) {
    493		pr_debug("%s clock disabled\n", clk_hw_get_name(hw));
    494		/* First put the CSR in reset */
    495		data = xgene_clk_read(pclk->param.csr_reg +
    496					pclk->param.reg_csr_offset);
    497		data |= pclk->param.reg_csr_mask;
    498		xgene_clk_write(data, pclk->param.csr_reg +
    499					pclk->param.reg_csr_offset);
    500
    501		/* Second disable the clock */
    502		data = xgene_clk_read(pclk->param.csr_reg +
    503					pclk->param.reg_clk_offset);
    504		data &= ~pclk->param.reg_clk_mask;
    505		xgene_clk_write(data, pclk->param.csr_reg +
    506					pclk->param.reg_clk_offset);
    507	}
    508
    509	if (pclk->lock)
    510		spin_unlock_irqrestore(pclk->lock, flags);
    511}
    512
    513static int xgene_clk_is_enabled(struct clk_hw *hw)
    514{
    515	struct xgene_clk *pclk = to_xgene_clk(hw);
    516	u32 data = 0;
    517
    518	if (pclk->param.csr_reg) {
    519		pr_debug("%s clock checking\n", clk_hw_get_name(hw));
    520		data = xgene_clk_read(pclk->param.csr_reg +
    521					pclk->param.reg_clk_offset);
    522		pr_debug("%s clock is %s\n", clk_hw_get_name(hw),
    523			data & pclk->param.reg_clk_mask ? "enabled" :
    524							"disabled");
    525	}
    526
    527	if (!pclk->param.csr_reg)
    528		return 1;
    529	return data & pclk->param.reg_clk_mask ? 1 : 0;
    530}
    531
    532static unsigned long xgene_clk_recalc_rate(struct clk_hw *hw,
    533				unsigned long parent_rate)
    534{
    535	struct xgene_clk *pclk = to_xgene_clk(hw);
    536	u32 data;
    537
    538	if (pclk->param.divider_reg) {
    539		data = xgene_clk_read(pclk->param.divider_reg +
    540					pclk->param.reg_divider_offset);
    541		data >>= pclk->param.reg_divider_shift;
    542		data &= (1 << pclk->param.reg_divider_width) - 1;
    543
    544		pr_debug("%s clock recalc rate %ld parent %ld\n",
    545			clk_hw_get_name(hw),
    546			parent_rate / data, parent_rate);
    547
    548		return parent_rate / data;
    549	} else {
    550		pr_debug("%s clock recalc rate %ld parent %ld\n",
    551			clk_hw_get_name(hw), parent_rate, parent_rate);
    552		return parent_rate;
    553	}
    554}
    555
    556static int xgene_clk_set_rate(struct clk_hw *hw, unsigned long rate,
    557				unsigned long parent_rate)
    558{
    559	struct xgene_clk *pclk = to_xgene_clk(hw);
    560	unsigned long flags = 0;
    561	u32 data;
    562	u32 divider;
    563	u32 divider_save;
    564
    565	if (pclk->lock)
    566		spin_lock_irqsave(pclk->lock, flags);
    567
    568	if (pclk->param.divider_reg) {
    569		/* Let's compute the divider */
    570		if (rate > parent_rate)
    571			rate = parent_rate;
    572		divider_save = divider = parent_rate / rate; /* Rounded down */
    573		divider &= (1 << pclk->param.reg_divider_width) - 1;
    574		divider <<= pclk->param.reg_divider_shift;
    575
    576		/* Set new divider */
    577		data = xgene_clk_read(pclk->param.divider_reg +
    578				pclk->param.reg_divider_offset);
    579		data &= ~(((1 << pclk->param.reg_divider_width) - 1)
    580				<< pclk->param.reg_divider_shift);
    581		data |= divider;
    582		xgene_clk_write(data, pclk->param.divider_reg +
    583					pclk->param.reg_divider_offset);
    584		pr_debug("%s clock set rate %ld\n", clk_hw_get_name(hw),
    585			parent_rate / divider_save);
    586	} else {
    587		divider_save = 1;
    588	}
    589
    590	if (pclk->lock)
    591		spin_unlock_irqrestore(pclk->lock, flags);
    592
    593	return parent_rate / divider_save;
    594}
    595
    596static long xgene_clk_round_rate(struct clk_hw *hw, unsigned long rate,
    597				unsigned long *prate)
    598{
    599	struct xgene_clk *pclk = to_xgene_clk(hw);
    600	unsigned long parent_rate = *prate;
    601	u32 divider;
    602
    603	if (pclk->param.divider_reg) {
    604		/* Let's compute the divider */
    605		if (rate > parent_rate)
    606			rate = parent_rate;
    607		divider = parent_rate / rate;   /* Rounded down */
    608	} else {
    609		divider = 1;
    610	}
    611
    612	return parent_rate / divider;
    613}
    614
    615static const struct clk_ops xgene_clk_ops = {
    616	.enable = xgene_clk_enable,
    617	.disable = xgene_clk_disable,
    618	.is_enabled = xgene_clk_is_enabled,
    619	.recalc_rate = xgene_clk_recalc_rate,
    620	.set_rate = xgene_clk_set_rate,
    621	.round_rate = xgene_clk_round_rate,
    622};
    623
    624static struct clk *xgene_register_clk(struct device *dev,
    625		const char *name, const char *parent_name,
    626		struct xgene_dev_parameters *parameters, spinlock_t *lock)
    627{
    628	struct xgene_clk *apmclk;
    629	struct clk *clk;
    630	struct clk_init_data init;
    631	int rc;
    632
    633	/* allocate the APM clock structure */
    634	apmclk = kzalloc(sizeof(*apmclk), GFP_KERNEL);
    635	if (!apmclk)
    636		return ERR_PTR(-ENOMEM);
    637
    638	init.name = name;
    639	init.ops = &xgene_clk_ops;
    640	init.flags = 0;
    641	init.parent_names = parent_name ? &parent_name : NULL;
    642	init.num_parents = parent_name ? 1 : 0;
    643
    644	apmclk->lock = lock;
    645	apmclk->hw.init = &init;
    646	apmclk->param = *parameters;
    647
    648	/* Register the clock */
    649	clk = clk_register(dev, &apmclk->hw);
    650	if (IS_ERR(clk)) {
    651		pr_err("%s: could not register clk %s\n", __func__, name);
    652		kfree(apmclk);
    653		return clk;
    654	}
    655
    656	/* Register the clock for lookup */
    657	rc = clk_register_clkdev(clk, name, NULL);
    658	if (rc != 0) {
    659		pr_err("%s: could not register lookup clk %s\n",
    660			__func__, name);
    661	}
    662	return clk;
    663}
    664
    665static void __init xgene_devclk_init(struct device_node *np)
    666{
    667	const char *clk_name = np->full_name;
    668	struct clk *clk;
    669	struct resource res;
    670	int rc;
    671	struct xgene_dev_parameters parameters;
    672	int i;
    673
    674	/* Check if the entry is disabled */
    675        if (!of_device_is_available(np))
    676                return;
    677
    678	/* Parse the DTS register for resource */
    679	parameters.csr_reg = NULL;
    680	parameters.divider_reg = NULL;
    681	for (i = 0; i < 2; i++) {
    682		void __iomem *map_res;
    683		rc = of_address_to_resource(np, i, &res);
    684		if (rc != 0) {
    685			if (i == 0) {
    686				pr_err("no DTS register for %pOF\n", np);
    687				return;
    688			}
    689			break;
    690		}
    691		map_res = of_iomap(np, i);
    692		if (!map_res) {
    693			pr_err("Unable to map resource %d for %pOF\n", i, np);
    694			goto err;
    695		}
    696		if (strcmp(res.name, "div-reg") == 0)
    697			parameters.divider_reg = map_res;
    698		else /* if (strcmp(res->name, "csr-reg") == 0) */
    699			parameters.csr_reg = map_res;
    700	}
    701	if (of_property_read_u32(np, "csr-offset", &parameters.reg_csr_offset))
    702		parameters.reg_csr_offset = 0;
    703	if (of_property_read_u32(np, "csr-mask", &parameters.reg_csr_mask))
    704		parameters.reg_csr_mask = 0xF;
    705	if (of_property_read_u32(np, "enable-offset",
    706				&parameters.reg_clk_offset))
    707		parameters.reg_clk_offset = 0x8;
    708	if (of_property_read_u32(np, "enable-mask", &parameters.reg_clk_mask))
    709		parameters.reg_clk_mask = 0xF;
    710	if (of_property_read_u32(np, "divider-offset",
    711				&parameters.reg_divider_offset))
    712		parameters.reg_divider_offset = 0;
    713	if (of_property_read_u32(np, "divider-width",
    714				&parameters.reg_divider_width))
    715		parameters.reg_divider_width = 0;
    716	if (of_property_read_u32(np, "divider-shift",
    717				&parameters.reg_divider_shift))
    718		parameters.reg_divider_shift = 0;
    719	of_property_read_string(np, "clock-output-names", &clk_name);
    720
    721	clk = xgene_register_clk(NULL, clk_name,
    722		of_clk_get_parent_name(np, 0), &parameters, &clk_lock);
    723	if (IS_ERR(clk))
    724		goto err;
    725	pr_debug("Add %s clock\n", clk_name);
    726	rc = of_clk_add_provider(np, of_clk_src_simple_get, clk);
    727	if (rc != 0)
    728		pr_err("%s: could register provider clk %pOF\n", __func__, np);
    729
    730	return;
    731
    732err:
    733	if (parameters.csr_reg)
    734		iounmap(parameters.csr_reg);
    735	if (parameters.divider_reg)
    736		iounmap(parameters.divider_reg);
    737}
    738
    739CLK_OF_DECLARE(xgene_socpll_clock, "apm,xgene-socpll-clock", xgene_socpllclk_init);
    740CLK_OF_DECLARE(xgene_pcppll_clock, "apm,xgene-pcppll-clock", xgene_pcppllclk_init);
    741CLK_OF_DECLARE(xgene_pmd_clock, "apm,xgene-pmd-clock", xgene_pmdclk_init);
    742CLK_OF_DECLARE(xgene_socpll_v2_clock, "apm,xgene-socpll-v2-clock",
    743	       xgene_socpllclk_init);
    744CLK_OF_DECLARE(xgene_pcppll_v2_clock, "apm,xgene-pcppll-v2-clock",
    745	       xgene_pcppllclk_init);
    746CLK_OF_DECLARE(xgene_dev_clock, "apm,xgene-device-clock", xgene_devclk_init);