#include <malloc.h>
#include <clk-uclass.h>
#include <dm/device.h>
+#include <dm/devres.h>
#include <dm/uclass.h>
#include <clk.h>
#include "clk.h"
+#include <linux/err.h>
#define UBOOT_DM_CLK_IMX_PLLV3_GENERIC "imx_clk_pllv3_generic"
#define UBOOT_DM_CLK_IMX_PLLV3_SYS "imx_clk_pllv3_sys"
#define UBOOT_DM_CLK_IMX_PLLV3_USB "imx_clk_pllv3_usb"
#define UBOOT_DM_CLK_IMX_PLLV3_AV "imx_clk_pllv3_av"
+#define UBOOT_DM_CLK_IMX_PLLV3_ENET "imx_clk_pllv3_enet"
#define PLL_NUM_OFFSET 0x10
#define PLL_DENOM_OFFSET 0x20
#define BM_PLL_POWER (0x1 << 12)
+#define BM_PLL_ENABLE (0x1 << 13)
#define BM_PLL_LOCK (0x1 << 31)
struct clk_pllv3 {
void __iomem *base;
u32 power_bit;
bool powerup_set;
+ u32 enable_bit;
u32 div_mask;
u32 div_shift;
+ unsigned long ref_clock;
};
#define to_clk_pllv3(_clk) container_of(_clk, struct clk_pllv3, clk)
val |= pll->power_bit;
else
val &= ~pll->power_bit;
+
+ val |= pll->enable_bit;
+
writel(val, pll->base);
return 0;
val &= ~pll->power_bit;
else
val |= pll->power_bit;
+
+ val &= ~pll->enable_bit;
+
writel(val, pll->base);
return 0;
{
struct clk_pllv3 *pll = to_clk_pllv3(clk);
unsigned long parent_rate = clk_get_parent_rate(clk);
- unsigned long min_rate = parent_rate * 54 / 2;
- unsigned long max_rate = parent_rate * 108 / 2;
+ unsigned long min_rate;
+ unsigned long max_rate;
u32 val, div;
+ if (parent_rate == 0)
+ return -EINVAL;
+
+ min_rate = parent_rate * 54 / 2;
+ max_rate = parent_rate * 108 / 2;
+
if (rate < min_rate || rate > max_rate)
return -EINVAL;
}
static const struct clk_ops clk_pllv3_sys_ops = {
- .enable = clk_pllv3_generic_enable,
+ .enable = clk_pllv3_generic_enable,
.disable = clk_pllv3_generic_disable,
.get_rate = clk_pllv3_sys_get_rate,
.set_rate = clk_pllv3_sys_set_rate,
u32 div = readl(pll->base) & pll->div_mask;
u64 temp64 = (u64)parent_rate;
+ if (mfd == 0)
+ return -EIO;
+
temp64 *= mfn;
do_div(temp64, mfd);
{
struct clk_pllv3 *pll = to_clk_pllv3(clk);
unsigned long parent_rate = clk_get_parent_rate(clk);
- unsigned long min_rate = parent_rate * 27;
- unsigned long max_rate = parent_rate * 54;
+ unsigned long min_rate;
+ unsigned long max_rate;
u32 val, div;
u32 mfn, mfd = 1000000;
u32 max_mfd = 0x3FFFFFFF;
u64 temp64;
+ if (parent_rate == 0)
+ return -EINVAL;
+
+ min_rate = parent_rate * 27;
+ max_rate = parent_rate * 54;
+
if (rate < min_rate || rate > max_rate)
return -EINVAL;
.set_rate = clk_pllv3_av_set_rate,
};
+static ulong clk_pllv3_enet_get_rate(struct clk *clk)
+{
+ struct clk_pllv3 *pll = to_clk_pllv3(clk);
+
+ return pll->ref_clock;
+}
+
+static const struct clk_ops clk_pllv3_enet_ops = {
+ .enable = clk_pllv3_generic_enable,
+ .disable = clk_pllv3_generic_disable,
+ .get_rate = clk_pllv3_enet_get_rate,
+};
+
struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
const char *parent_name, void __iomem *base,
u32 div_mask)
return ERR_PTR(-ENOMEM);
pll->power_bit = BM_PLL_POWER;
+ pll->enable_bit = BM_PLL_ENABLE;
switch (type) {
case IMX_PLLV3_GENERIC:
pll->div_shift = 0;
pll->powerup_set = false;
break;
+ case IMX_PLLV3_ENET:
+ drv_name = UBOOT_DM_CLK_IMX_PLLV3_ENET;
+ pll->ref_clock = 500000000;
+ break;
default:
kfree(pll);
- return ERR_PTR(-ENOTSUPP);
+ return ERR_PTR(-EINVAL);
}
pll->base = base;
.ops = &clk_pllv3_av_ops,
.flags = DM_FLAG_PRE_RELOC,
};
+
+U_BOOT_DRIVER(clk_pllv3_enet) = {
+ .name = UBOOT_DM_CLK_IMX_PLLV3_ENET,
+ .id = UCLASS_CLK,
+ .ops = &clk_pllv3_enet_ops,
+};