1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2018 Amarula Solutions. 4 * Author: Jagan Teki <jagan@amarulasolutions.com> 5 */ 6 7#include <common.h> 8#include <clk-uclass.h> 9#include <dm.h> 10#include <errno.h> 11#include <log.h> 12#include <reset.h> 13#include <asm/io.h> 14#include <clk/sunxi.h> 15#include <dm/device-internal.h> 16#include <linux/bitops.h> 17#include <linux/log2.h> 18 19extern U_BOOT_DRIVER(sunxi_reset); 20 21static const struct ccu_clk_gate *plat_to_gate(struct ccu_plat *plat, 22 unsigned long id) 23{ 24 if (id >= plat->desc->num_gates) 25 return NULL; 26 27 return &plat->desc->gates[id]; 28} 29 30static int sunxi_set_gate(struct clk *clk, bool on) 31{ 32 struct ccu_plat *plat = dev_get_plat(clk->dev); 33 const struct ccu_clk_gate *gate = plat_to_gate(plat, clk->id); 34 u32 reg; 35 36 if (gate && (gate->flags & CCU_CLK_F_DUMMY_GATE)) 37 return 0; 38 39 if (!gate || !(gate->flags & CCU_CLK_F_IS_VALID)) { 40 printf("%s: (CLK#%ld) unhandled\n", __func__, clk->id); 41 return 0; 42 } 43 44 debug("%s: (CLK#%ld) off#0x%x, BIT(%d)\n", __func__, 45 clk->id, gate->off, ilog2(gate->bit)); 46 47 reg = readl(plat->base + gate->off); 48 if (on) 49 reg |= gate->bit; 50 else 51 reg &= ~gate->bit; 52 53 writel(reg, plat->base + gate->off); 54 55 return 0; 56} 57 58static int sunxi_clk_enable(struct clk *clk) 59{ 60 return sunxi_set_gate(clk, true); 61} 62 63static int sunxi_clk_disable(struct clk *clk) 64{ 65 return sunxi_set_gate(clk, false); 66} 67 68struct clk_ops sunxi_clk_ops = { 69 .enable = sunxi_clk_enable, 70 .disable = sunxi_clk_disable, 71}; 72 73static int sunxi_clk_bind(struct udevice *dev) 74{ 75 /* Reuse the platform data for the reset driver. */ 76 return device_bind(dev, DM_DRIVER_REF(sunxi_reset), "reset", 77 dev_get_plat(dev), dev_ofnode(dev), NULL); 78} 79 80static int sunxi_clk_probe(struct udevice *dev) 81{ 82 struct clk_bulk clk_bulk; 83 struct reset_ctl_bulk rst_bulk; 84 int ret; 85 86 ret = clk_get_bulk(dev, &clk_bulk); 87 if (!ret) 88 clk_enable_bulk(&clk_bulk); 89 90 ret = reset_get_bulk(dev, &rst_bulk); 91 if (!ret) 92 reset_deassert_bulk(&rst_bulk); 93 94 return 0; 95} 96 97static int sunxi_clk_of_to_plat(struct udevice *dev) 98{ 99 struct ccu_plat *plat = dev_get_plat(dev); 100 101 plat->base = dev_read_addr_ptr(dev); 102 if (!plat->base) 103 return -ENOMEM; 104 105 plat->desc = (const struct ccu_desc *)dev_get_driver_data(dev); 106 if (!plat->desc) 107 return -EINVAL; 108 109 return 0; 110} 111 112extern const struct ccu_desc a10_ccu_desc; 113extern const struct ccu_desc a10s_ccu_desc; 114extern const struct ccu_desc a23_ccu_desc; 115extern const struct ccu_desc a31_ccu_desc; 116extern const struct ccu_desc a31_r_ccu_desc; 117extern const struct ccu_desc a64_ccu_desc; 118extern const struct ccu_desc a80_ccu_desc; 119extern const struct ccu_desc a80_mmc_clk_desc; 120extern const struct ccu_desc a83t_ccu_desc; 121extern const struct ccu_desc d1_ccu_desc; 122extern const struct ccu_desc f1c100s_ccu_desc; 123extern const struct ccu_desc h3_ccu_desc; 124extern const struct ccu_desc h6_ccu_desc; 125extern const struct ccu_desc h616_ccu_desc; 126extern const struct ccu_desc h6_r_ccu_desc; 127extern const struct ccu_desc r40_ccu_desc; 128extern const struct ccu_desc v3s_ccu_desc; 129 130static const struct udevice_id sunxi_clk_ids[] = { 131#ifdef CONFIG_CLK_SUN4I_A10 132 { .compatible = "allwinner,sun4i-a10-ccu", 133 .data = (ulong)&a10_ccu_desc }, 134#endif 135#ifdef CONFIG_CLK_SUN5I_A10S 136 { .compatible = "allwinner,sun5i-a10s-ccu", 137 .data = (ulong)&a10s_ccu_desc }, 138 { .compatible = "allwinner,sun5i-a13-ccu", 139 .data = (ulong)&a10s_ccu_desc }, 140#endif 141#ifdef CONFIG_CLK_SUN6I_A31 142 { .compatible = "allwinner,sun6i-a31-ccu", 143 .data = (ulong)&a31_ccu_desc }, 144#endif 145#ifdef CONFIG_CLK_SUN4I_A10 146 { .compatible = "allwinner,sun7i-a20-ccu", 147 .data = (ulong)&a10_ccu_desc }, 148#endif 149#ifdef CONFIG_CLK_SUN8I_A23 150 { .compatible = "allwinner,sun8i-a23-ccu", 151 .data = (ulong)&a23_ccu_desc }, 152 { .compatible = "allwinner,sun8i-a33-ccu", 153 .data = (ulong)&a23_ccu_desc }, 154#endif 155#ifdef CONFIG_CLK_SUN8I_A83T 156 { .compatible = "allwinner,sun8i-a83t-ccu", 157 .data = (ulong)&a83t_ccu_desc }, 158#endif 159#ifdef CONFIG_CLK_SUN6I_A31_R 160 { .compatible = "allwinner,sun8i-a83t-r-ccu", 161 .data = (ulong)&a31_r_ccu_desc }, 162#endif 163#ifdef CONFIG_CLK_SUN8I_H3 164 { .compatible = "allwinner,sun8i-h3-ccu", 165 .data = (ulong)&h3_ccu_desc }, 166#endif 167#ifdef CONFIG_CLK_SUN6I_A31_R 168 { .compatible = "allwinner,sun8i-h3-r-ccu", 169 .data = (ulong)&a31_r_ccu_desc }, 170#endif 171#ifdef CONFIG_CLK_SUN8I_R40 172 { .compatible = "allwinner,sun8i-r40-ccu", 173 .data = (ulong)&r40_ccu_desc }, 174#endif 175#ifdef CONFIG_CLK_SUN8I_V3S 176 { .compatible = "allwinner,sun8i-v3-ccu", 177 .data = (ulong)&v3s_ccu_desc }, 178 { .compatible = "allwinner,sun8i-v3s-ccu", 179 .data = (ulong)&v3s_ccu_desc }, 180#endif 181#ifdef CONFIG_CLK_SUN9I_A80 182 { .compatible = "allwinner,sun9i-a80-ccu", 183 .data = (ulong)&a80_ccu_desc }, 184 { .compatible = "allwinner,sun9i-a80-mmc-config-clk", 185 .data = (ulong)&a80_mmc_clk_desc }, 186#endif 187#ifdef CONFIG_CLK_SUN50I_A64 188 { .compatible = "allwinner,sun50i-a64-ccu", 189 .data = (ulong)&a64_ccu_desc }, 190#endif 191#ifdef CONFIG_CLK_SUN6I_A31_R 192 { .compatible = "allwinner,sun50i-a64-r-ccu", 193 .data = (ulong)&a31_r_ccu_desc }, 194#endif 195#ifdef CONFIG_CLK_SUN8I_H3 196 { .compatible = "allwinner,sun50i-h5-ccu", 197 .data = (ulong)&h3_ccu_desc }, 198#endif 199#ifdef CONFIG_CLK_SUN20I_D1 200 { .compatible = "allwinner,sun20i-d1-ccu", 201 .data = (ulong)&d1_ccu_desc }, 202#endif 203#ifdef CONFIG_CLK_SUN50I_H6 204 { .compatible = "allwinner,sun50i-h6-ccu", 205 .data = (ulong)&h6_ccu_desc }, 206#endif 207#ifdef CONFIG_CLK_SUN50I_H6_R 208 { .compatible = "allwinner,sun50i-h6-r-ccu", 209 .data = (ulong)&h6_r_ccu_desc }, 210#endif 211#ifdef CONFIG_CLK_SUN50I_H616 212 { .compatible = "allwinner,sun50i-h616-ccu", 213 .data = (ulong)&h616_ccu_desc }, 214#endif 215#ifdef CONFIG_CLK_SUN50I_H6_R 216 { .compatible = "allwinner,sun50i-h616-r-ccu", 217 .data = (ulong)&h6_r_ccu_desc }, 218#endif 219#ifdef CONFIG_CLK_SUNIV_F1C100S 220 { .compatible = "allwinner,suniv-f1c100s-ccu", 221 .data = (ulong)&f1c100s_ccu_desc }, 222#endif 223 { } 224}; 225 226U_BOOT_DRIVER(sunxi_clk) = { 227 .name = "sunxi_clk", 228 .id = UCLASS_CLK, 229 .of_match = sunxi_clk_ids, 230 .bind = sunxi_clk_bind, 231 .probe = sunxi_clk_probe, 232 .of_to_plat = sunxi_clk_of_to_plat, 233 .plat_auto = sizeof(struct ccu_plat), 234 .ops = &sunxi_clk_ops, 235}; 236