blob: a721dbee943be99287dbf86865bc05da867383fb [file] [log] [blame]
Lukasz Majewski1d7993d2019-06-24 15:50:45 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2019 DENX Software Engineering
4 * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
5 */
6
7#include <common.h>
8#include <asm/io.h>
9#include <malloc.h>
10#include <clk-uclass.h>
11#include <dm/device.h>
12#include <dm/uclass.h>
13#include <clk.h>
14#include "clk.h"
15
Giulio Benetti16faa592020-01-10 15:46:53 +010016#define UBOOT_DM_CLK_IMX_PLLV3_GENERIC "imx_clk_pllv3_generic"
17#define UBOOT_DM_CLK_IMX_PLLV3_USB "imx_clk_pllv3_usb"
Lukasz Majewski1d7993d2019-06-24 15:50:45 +020018
Giulio Benettif4b70942020-01-10 15:46:55 +010019#define BM_PLL_POWER (0x1 << 12)
Giulio Benetti9841fee2020-01-10 15:46:57 +010020#define BM_PLL_LOCK (0x1 << 31)
Giulio Benettif4b70942020-01-10 15:46:55 +010021
Lukasz Majewski1d7993d2019-06-24 15:50:45 +020022struct clk_pllv3 {
23 struct clk clk;
24 void __iomem *base;
Giulio Benettif4b70942020-01-10 15:46:55 +010025 u32 power_bit;
26 bool powerup_set;
Lukasz Majewski1d7993d2019-06-24 15:50:45 +020027 u32 div_mask;
28 u32 div_shift;
29};
30
31#define to_clk_pllv3(_clk) container_of(_clk, struct clk_pllv3, clk)
32
Giulio Benetti16faa592020-01-10 15:46:53 +010033static ulong clk_pllv3_generic_get_rate(struct clk *clk)
Lukasz Majewski1d7993d2019-06-24 15:50:45 +020034{
35 struct clk_pllv3 *pll = to_clk_pllv3(dev_get_clk_ptr(clk->dev));
36 unsigned long parent_rate = clk_get_parent_rate(clk);
37
38 u32 div = (readl(pll->base) >> pll->div_shift) & pll->div_mask;
39
40 return (div == 1) ? parent_rate * 22 : parent_rate * 20;
41}
42
Giulio Benetti9841fee2020-01-10 15:46:57 +010043static ulong clk_pllv3_generic_set_rate(struct clk *clk, ulong rate)
44{
45 struct clk_pllv3 *pll = to_clk_pllv3(clk);
46 unsigned long parent_rate = clk_get_parent_rate(clk);
47 u32 val, div;
48
49 if (rate == parent_rate * 22)
50 div = 1;
51 else if (rate == parent_rate * 20)
52 div = 0;
53 else
54 return -EINVAL;
55
56 val = readl(pll->base);
57 val &= ~(pll->div_mask << pll->div_shift);
58 val |= (div << pll->div_shift);
59 writel(val, pll->base);
60
61 /* Wait for PLL to lock */
62 while (!(readl(pll->base) & BM_PLL_LOCK))
63 ;
64
65 return 0;
66}
67
Giulio Benettif4b70942020-01-10 15:46:55 +010068static int clk_pllv3_generic_enable(struct clk *clk)
69{
70 struct clk_pllv3 *pll = to_clk_pllv3(clk);
71 u32 val;
72
73 val = readl(pll->base);
74 if (pll->powerup_set)
75 val |= pll->power_bit;
76 else
77 val &= ~pll->power_bit;
78 writel(val, pll->base);
79
80 return 0;
81}
82
Giulio Benetticbb20012020-01-10 15:46:56 +010083static int clk_pllv3_generic_disable(struct clk *clk)
84{
85 struct clk_pllv3 *pll = to_clk_pllv3(clk);
86 u32 val;
87
88 val = readl(pll->base);
89 if (pll->powerup_set)
90 val &= ~pll->power_bit;
91 else
92 val |= pll->power_bit;
93 writel(val, pll->base);
94
95 return 0;
96}
97
Lukasz Majewski1d7993d2019-06-24 15:50:45 +020098static const struct clk_ops clk_pllv3_generic_ops = {
Giulio Benetti16faa592020-01-10 15:46:53 +010099 .get_rate = clk_pllv3_generic_get_rate,
Giulio Benettif4b70942020-01-10 15:46:55 +0100100 .enable = clk_pllv3_generic_enable,
Giulio Benetticbb20012020-01-10 15:46:56 +0100101 .disable = clk_pllv3_generic_disable,
Giulio Benetti9841fee2020-01-10 15:46:57 +0100102 .set_rate = clk_pllv3_generic_set_rate,
Lukasz Majewski1d7993d2019-06-24 15:50:45 +0200103};
104
105struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
106 const char *parent_name, void __iomem *base,
107 u32 div_mask)
108{
109 struct clk_pllv3 *pll;
110 struct clk *clk;
111 char *drv_name;
112 int ret;
113
114 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
115 if (!pll)
116 return ERR_PTR(-ENOMEM);
117
Giulio Benettif4b70942020-01-10 15:46:55 +0100118 pll->power_bit = BM_PLL_POWER;
119
Lukasz Majewski1d7993d2019-06-24 15:50:45 +0200120 switch (type) {
121 case IMX_PLLV3_GENERIC:
Giulio Benetti16faa592020-01-10 15:46:53 +0100122 drv_name = UBOOT_DM_CLK_IMX_PLLV3_GENERIC;
Giulio Benetti4abd8072020-01-10 15:46:54 +0100123 pll->div_shift = 0;
Giulio Benettif4b70942020-01-10 15:46:55 +0100124 pll->powerup_set = false;
Giulio Benetti16faa592020-01-10 15:46:53 +0100125 break;
Lukasz Majewski1d7993d2019-06-24 15:50:45 +0200126 case IMX_PLLV3_USB:
Giulio Benetti16faa592020-01-10 15:46:53 +0100127 drv_name = UBOOT_DM_CLK_IMX_PLLV3_USB;
Giulio Benetti4abd8072020-01-10 15:46:54 +0100128 pll->div_shift = 1;
Giulio Benettif4b70942020-01-10 15:46:55 +0100129 pll->powerup_set = true;
Lukasz Majewski1d7993d2019-06-24 15:50:45 +0200130 break;
131 default:
132 kfree(pll);
133 return ERR_PTR(-ENOTSUPP);
134 }
135
136 pll->base = base;
137 pll->div_mask = div_mask;
138 clk = &pll->clk;
139
140 ret = clk_register(clk, drv_name, name, parent_name);
141 if (ret) {
142 kfree(pll);
143 return ERR_PTR(ret);
144 }
145
146 return clk;
147}
148
149U_BOOT_DRIVER(clk_pllv3_generic) = {
Giulio Benetti16faa592020-01-10 15:46:53 +0100150 .name = UBOOT_DM_CLK_IMX_PLLV3_GENERIC,
151 .id = UCLASS_CLK,
152 .ops = &clk_pllv3_generic_ops,
153 .flags = DM_FLAG_PRE_RELOC,
154};
155
156U_BOOT_DRIVER(clk_pllv3_usb) = {
157 .name = UBOOT_DM_CLK_IMX_PLLV3_USB,
Lukasz Majewski1d7993d2019-06-24 15:50:45 +0200158 .id = UCLASS_CLK,
159 .ops = &clk_pllv3_generic_ops,
160 .flags = DM_FLAG_PRE_RELOC,
161};