1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Actions Semi S900 clock driver 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 <asm/arch-owl/clk_s900.h> 12 #include <asm/arch-owl/regs_s900.h> 13 #include <asm/io.h> 14 15 #include <dt-bindings/clock/s900_cmu.h> 16 17 void owl_clk_init(struct owl_clk_priv *priv) 18 { 19 u32 bus_clk = 0, core_pll, dev_pll; 20 21 /* Enable ASSIST_PLL */ 22 setbits_le32(priv->base + CMU_ASSISTPLL, BIT(0)); 23 24 udelay(PLL_STABILITY_WAIT_US); 25 26 /* Source HOSC to DEV_CLK */ 27 clrbits_le32(priv->base + CMU_DEVPLL, CMU_DEVPLL_CLK); 28 29 /* Configure BUS_CLK */ 30 bus_clk |= (CMU_PDBGDIV_DIV | CMU_PERDIV_DIV | CMU_NOCDIV_DIV | 31 CMU_DMMCLK_SRC | CMU_APBCLK_DIV | CMU_AHBCLK_DIV | 32 CMU_NOCCLK_SRC | CMU_CORECLK_HOSC); 33 writel(bus_clk, priv->base + CMU_BUSCLK); 34 35 udelay(PLL_STABILITY_WAIT_US); 36 37 /* Configure CORE_PLL */ 38 core_pll = readl(priv->base + CMU_COREPLL); 39 core_pll |= (CMU_COREPLL_EN | CMU_COREPLL_HOSC_EN | CMU_COREPLL_OUT); 40 writel(core_pll, priv->base + CMU_COREPLL); 41 42 udelay(PLL_STABILITY_WAIT_US); 43 44 /* Configure DEV_PLL */ 45 dev_pll = readl(priv->base + CMU_DEVPLL); 46 dev_pll |= (CMU_DEVPLL_EN | CMU_DEVPLL_OUT); 47 writel(dev_pll, priv->base + CMU_DEVPLL); 48 49 udelay(PLL_STABILITY_WAIT_US); 50 51 /* Source CORE_PLL for CORE_CLK */ 52 clrsetbits_le32(priv->base + CMU_BUSCLK, CMU_CORECLK_MASK, 53 CMU_CORECLK_CPLL); 54 55 /* Source DEV_PLL for DEV_CLK */ 56 setbits_le32(priv->base + CMU_DEVPLL, CMU_DEVPLL_CLK); 57 58 udelay(PLL_STABILITY_WAIT_US); 59 } 60 61 void owl_uart_clk_enable(struct owl_clk_priv *priv) 62 { 63 /* Source HOSC for UART5 interface */ 64 clrbits_le32(priv->base + CMU_UART5CLK, CMU_UARTCLK_SRC_DEVPLL); 65 66 /* Enable UART5 interface clock */ 67 setbits_le32(priv->base + CMU_DEVCLKEN1, CMU_DEVCLKEN1_UART5); 68 } 69 70 void owl_uart_clk_disable(struct owl_clk_priv *priv) 71 { 72 /* Disable UART5 interface clock */ 73 clrbits_le32(priv->base + CMU_DEVCLKEN1, CMU_DEVCLKEN1_UART5); 74 } 75 76 int owl_clk_enable(struct clk *clk) 77 { 78 struct owl_clk_priv *priv = dev_get_priv(clk->dev); 79 80 switch (clk->id) { 81 case CLOCK_UART5: 82 owl_uart_clk_enable(priv); 83 break; 84 default: 85 return 0; 86 } 87 88 return 0; 89 } 90 91 int owl_clk_disable(struct clk *clk) 92 { 93 struct owl_clk_priv *priv = dev_get_priv(clk->dev); 94 95 switch (clk->id) { 96 case CLOCK_UART5: 97 owl_uart_clk_disable(priv); 98 break; 99 default: 100 return 0; 101 } 102 103 return 0; 104 } 105 106 static int owl_clk_probe(struct udevice *dev) 107 { 108 struct owl_clk_priv *priv = dev_get_priv(dev); 109 110 priv->base = dev_read_addr(dev); 111 if (priv->base == FDT_ADDR_T_NONE) 112 return -EINVAL; 113 114 /* setup necessary clocks */ 115 owl_clk_init(priv); 116 117 return 0; 118 } 119 120 static struct clk_ops owl_clk_ops = { 121 .enable = owl_clk_enable, 122 .disable = owl_clk_disable, 123 }; 124 125 static const struct udevice_id owl_clk_ids[] = { 126 { .compatible = "actions,s900-cmu" }, 127 { } 128 }; 129 130 U_BOOT_DRIVER(clk_owl) = { 131 .name = "clk_s900", 132 .id = UCLASS_CLK, 133 .of_match = owl_clk_ids, 134 .ops = &owl_clk_ops, 135 .priv_auto_alloc_size = sizeof(struct owl_clk_priv), 136 .probe = owl_clk_probe, 137 .flags = DM_FLAG_PRE_RELOC, 138 }; 139