1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * 4 * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com> 5 * Copyright (C) 2010 John Crispin <john@phrozen.org> 6 */ 7 #include <linux/io.h> 8 #include <linux/export.h> 9 #include <linux/init.h> 10 #include <linux/kernel.h> 11 #include <linux/types.h> 12 #include <linux/clk.h> 13 #include <linux/clkdev.h> 14 #include <linux/err.h> 15 #include <linux/list.h> 16 17 #include <asm/time.h> 18 #include <asm/irq.h> 19 #include <asm/div64.h> 20 21 #include <lantiq_soc.h> 22 23 #include "clk.h" 24 #include "prom.h" 25 26 /* lantiq socs have 3 static clocks */ 27 static struct clk cpu_clk_generic[4]; 28 29 void clkdev_add_static(unsigned long cpu, unsigned long fpi, 30 unsigned long io, unsigned long ppe) 31 { 32 cpu_clk_generic[0].rate = cpu; 33 cpu_clk_generic[1].rate = fpi; 34 cpu_clk_generic[2].rate = io; 35 cpu_clk_generic[3].rate = ppe; 36 } 37 38 struct clk *clk_get_cpu(void) 39 { 40 return &cpu_clk_generic[0]; 41 } 42 43 struct clk *clk_get_fpi(void) 44 { 45 return &cpu_clk_generic[1]; 46 } 47 EXPORT_SYMBOL_GPL(clk_get_fpi); 48 49 struct clk *clk_get_io(void) 50 { 51 return &cpu_clk_generic[2]; 52 } 53 EXPORT_SYMBOL_GPL(clk_get_io); 54 55 struct clk *clk_get_ppe(void) 56 { 57 return &cpu_clk_generic[3]; 58 } 59 EXPORT_SYMBOL_GPL(clk_get_ppe); 60 61 static inline int clk_good(struct clk *clk) 62 { 63 return clk && !IS_ERR(clk); 64 } 65 66 unsigned long clk_get_rate(struct clk *clk) 67 { 68 if (unlikely(!clk_good(clk))) 69 return 0; 70 71 if (clk->rate != 0) 72 return clk->rate; 73 74 if (clk->get_rate != NULL) 75 return clk->get_rate(); 76 77 return 0; 78 } 79 EXPORT_SYMBOL(clk_get_rate); 80 81 int clk_set_rate(struct clk *clk, unsigned long rate) 82 { 83 if (unlikely(!clk_good(clk))) 84 return 0; 85 if (clk->rates && *clk->rates) { 86 unsigned long *r = clk->rates; 87 88 while (*r && (*r != rate)) 89 r++; 90 if (!*r) { 91 pr_err("clk %s.%s: trying to set invalid rate %ld\n", 92 clk->cl.dev_id, clk->cl.con_id, rate); 93 return -1; 94 } 95 } 96 clk->rate = rate; 97 return 0; 98 } 99 EXPORT_SYMBOL(clk_set_rate); 100 101 long clk_round_rate(struct clk *clk, unsigned long rate) 102 { 103 if (unlikely(!clk_good(clk))) 104 return 0; 105 if (clk->rates && *clk->rates) { 106 unsigned long *r = clk->rates; 107 108 while (*r && (*r != rate)) 109 r++; 110 if (!*r) { 111 return clk->rate; 112 } 113 } 114 return rate; 115 } 116 EXPORT_SYMBOL(clk_round_rate); 117 118 int clk_enable(struct clk *clk) 119 { 120 if (unlikely(!clk_good(clk))) 121 return -1; 122 123 if (clk->enable) 124 return clk->enable(clk); 125 126 return -1; 127 } 128 EXPORT_SYMBOL(clk_enable); 129 130 void clk_disable(struct clk *clk) 131 { 132 if (unlikely(!clk_good(clk))) 133 return; 134 135 if (clk->disable) 136 clk->disable(clk); 137 } 138 EXPORT_SYMBOL(clk_disable); 139 140 int clk_activate(struct clk *clk) 141 { 142 if (unlikely(!clk_good(clk))) 143 return -1; 144 145 if (clk->activate) 146 return clk->activate(clk); 147 148 return -1; 149 } 150 EXPORT_SYMBOL(clk_activate); 151 152 void clk_deactivate(struct clk *clk) 153 { 154 if (unlikely(!clk_good(clk))) 155 return; 156 157 if (clk->deactivate) 158 clk->deactivate(clk); 159 } 160 EXPORT_SYMBOL(clk_deactivate); 161 162 struct clk *clk_get_parent(struct clk *clk) 163 { 164 return NULL; 165 } 166 EXPORT_SYMBOL(clk_get_parent); 167 168 int clk_set_parent(struct clk *clk, struct clk *parent) 169 { 170 return 0; 171 } 172 EXPORT_SYMBOL(clk_set_parent); 173 174 static inline u32 get_counter_resolution(void) 175 { 176 u32 res; 177 178 __asm__ __volatile__( 179 ".set push\n" 180 ".set mips32r2\n" 181 "rdhwr %0, $3\n" 182 ".set pop\n" 183 : "=&r" (res) 184 : /* no input */ 185 : "memory"); 186 187 return res; 188 } 189 190 void __init plat_time_init(void) 191 { 192 struct clk *clk; 193 194 ltq_soc_init(); 195 196 clk = clk_get_cpu(); 197 mips_hpt_frequency = clk_get_rate(clk) / get_counter_resolution(); 198 write_c0_compare(read_c0_count()); 199 pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000); 200 clk_put(clk); 201 } 202