5607b2b7b51675aafcc86b038e346c7c72cf7804
[oweals/u-boot.git] / drivers / clk / owl / clk_owl.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Common clock driver for Actions Semi SoCs.
4  *
5  * Copyright (C) 2015 Actions Semi Co., Ltd.
6  * Copyright (C) 2018 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
7  */
8
9 #include <common.h>
10 #include <dm.h>
11 #include "clk_owl.h"
12 #include <asm/io.h>
13 #if defined(CONFIG_MACH_S900)
14 #include <asm/arch-owl/regs_s900.h>
15 #include <dt-bindings/clock/actions,s900-cmu.h>
16 #elif defined(CONFIG_MACH_S700)
17 #include <asm/arch-owl/regs_s700.h>
18 #include <dt-bindings/clock/actions,s700-cmu.h>
19 #endif
20
21 void owl_clk_init(struct owl_clk_priv *priv)
22 {
23         u32 bus_clk = 0, core_pll, dev_pll;
24
25 #if defined(CONFIG_MACH_S900)
26         /* Enable ASSIST_PLL */
27         setbits_le32(priv->base + CMU_ASSISTPLL, BIT(0));
28         udelay(PLL_STABILITY_WAIT_US);
29 #endif
30
31         /* Source HOSC to DEV_CLK */
32         clrbits_le32(priv->base + CMU_DEVPLL, CMU_DEVPLL_CLK);
33
34         /* Configure BUS_CLK */
35         bus_clk |= (CMU_PDBGDIV_DIV | CMU_PERDIV_DIV | CMU_NOCDIV_DIV |
36                         CMU_DMMCLK_SRC | CMU_APBCLK_DIV | CMU_AHBCLK_DIV |
37                         CMU_NOCCLK_SRC | CMU_CORECLK_HOSC);
38         writel(bus_clk, priv->base + CMU_BUSCLK);
39
40         udelay(PLL_STABILITY_WAIT_US);
41
42         /* Configure CORE_PLL */
43         core_pll = readl(priv->base + CMU_COREPLL);
44         core_pll |= (CMU_COREPLL_EN | CMU_COREPLL_HOSC_EN | CMU_COREPLL_OUT);
45         writel(core_pll, priv->base + CMU_COREPLL);
46
47         udelay(PLL_STABILITY_WAIT_US);
48
49         /* Configure DEV_PLL */
50         dev_pll = readl(priv->base + CMU_DEVPLL);
51         dev_pll |= (CMU_DEVPLL_EN | CMU_DEVPLL_OUT);
52         writel(dev_pll, priv->base + CMU_DEVPLL);
53
54         udelay(PLL_STABILITY_WAIT_US);
55
56         /* Source CORE_PLL for CORE_CLK */
57         clrsetbits_le32(priv->base + CMU_BUSCLK, CMU_CORECLK_MASK,
58                         CMU_CORECLK_CPLL);
59
60         /* Source DEV_PLL for DEV_CLK */
61         setbits_le32(priv->base + CMU_DEVPLL, CMU_DEVPLL_CLK);
62
63         udelay(PLL_STABILITY_WAIT_US);
64 }
65
66 int owl_clk_enable(struct clk *clk)
67 {
68         struct owl_clk_priv *priv = dev_get_priv(clk->dev);
69         enum owl_soc model = dev_get_driver_data(clk->dev);
70
71         switch (clk->id) {
72         case CLK_UART5:
73                 if (model != S900)
74                         return -EINVAL;
75                 /* Source HOSC for UART5 interface */
76                 clrbits_le32(priv->base + CMU_UART5CLK, CMU_UARTCLK_SRC_DEVPLL);
77                 /* Enable UART5 interface clock */
78                 setbits_le32(priv->base + CMU_DEVCLKEN1, CMU_DEVCLKEN1_UART5);
79                 break;
80         case CLK_UART3:
81                 if (model != S700)
82                         return -EINVAL;
83                 /* Source HOSC for UART3 interface */
84                 clrbits_le32(priv->base + CMU_UART3CLK, CMU_UARTCLK_SRC_DEVPLL);
85                 /* Enable UART3 interface clock */
86                 setbits_le32(priv->base + CMU_DEVCLKEN1, CMU_DEVCLKEN1_UART3);
87                 break;
88         default:
89                 return -EINVAL;
90         }
91
92         return 0;
93 }
94
95 int owl_clk_disable(struct clk *clk)
96 {
97         struct owl_clk_priv *priv = dev_get_priv(clk->dev);
98         enum owl_soc model = dev_get_driver_data(clk->dev);
99
100         switch (clk->id) {
101         case CLK_UART5:
102                 if (model != S900)
103                         return -EINVAL;
104                 /* Disable UART5 interface clock */
105                 clrbits_le32(priv->base + CMU_DEVCLKEN1, CMU_DEVCLKEN1_UART5);
106                 break;
107         case CLK_UART3:
108                 if (model != S700)
109                         return -EINVAL;
110                 /* Disable UART3 interface clock */
111                 clrbits_le32(priv->base + CMU_DEVCLKEN1, CMU_DEVCLKEN1_UART3);
112                 break;
113         default:
114                 return -EINVAL;
115         }
116
117         return 0;
118 }
119
120 static int owl_clk_probe(struct udevice *dev)
121 {
122         struct owl_clk_priv *priv = dev_get_priv(dev);
123
124         priv->base = dev_read_addr(dev);
125         if (priv->base == FDT_ADDR_T_NONE)
126                 return -EINVAL;
127
128         /* setup necessary clocks */
129         owl_clk_init(priv);
130
131         return 0;
132 }
133
134 static const struct clk_ops owl_clk_ops = {
135         .enable = owl_clk_enable,
136         .disable = owl_clk_disable,
137 };
138
139 static const struct udevice_id owl_clk_ids[] = {
140 #if defined(CONFIG_MACH_S900)
141         { .compatible = "actions,s900-cmu", .data = S900 },
142 #elif defined(CONFIG_MACH_S700)
143         { .compatible = "actions,s700-cmu", .data = S700 },
144 #endif
145         { }
146 };
147
148 U_BOOT_DRIVER(clk_owl) = {
149         .name           = "clk_owl",
150         .id             = UCLASS_CLK,
151         .of_match       = owl_clk_ids,
152         .ops            = &owl_clk_ops,
153         .priv_auto_alloc_size = sizeof(struct owl_clk_priv),
154         .probe          = owl_clk_probe,
155 };