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 54 struct clk *clk_get_ppe(void) 55 { 56 return &cpu_clk_generic[3]; 57 } 58 EXPORT_SYMBOL_GPL(clk_get_ppe); 59 60 static inline int clk_good(struct clk *clk) 61 { 62 return clk && !IS_ERR(clk); 63 } 64 65 unsigned long clk_get_rate(struct clk *clk) 66 { 67 if (unlikely(!clk_good(clk))) 68 return 0; 69 70 if (clk->rate != 0) 71 return clk->rate; 72 73 if (clk->get_rate != NULL) 74 return clk->get_rate(); 75 76 return 0; 77 } 78 EXPORT_SYMBOL(clk_get_rate); 79 80 int clk_set_rate(struct clk *clk, unsigned long rate) 81 { 82 if (unlikely(!clk_good(clk))) 83 return 0; 84 if (clk->rates && *clk->rates) { 85 unsigned long *r = clk->rates; 86 87 while (*r && (*r != rate)) 88 r++; 89 if (!*r) { 90 pr_err("clk %s.%s: trying to set invalid rate %ld\n", 91 clk->cl.dev_id, clk->cl.con_id, rate); 92 return -1; 93 } 94 } 95 clk->rate = rate; 96 return 0; 97 } 98 EXPORT_SYMBOL(clk_set_rate); 99 100 long clk_round_rate(struct clk *clk, unsigned long rate) 101 { 102 if (unlikely(!clk_good(clk))) 103 return 0; 104 if (clk->rates && *clk->rates) { 105 unsigned long *r = clk->rates; 106 107 while (*r && (*r != rate)) 108 r++; 109 if (!*r) { 110 return clk->rate; 111 } 112 } 113 return rate; 114 } 115 EXPORT_SYMBOL(clk_round_rate); 116 117 int clk_enable(struct clk *clk) 118 { 119 if (unlikely(!clk_good(clk))) 120 return -1; 121 122 if (clk->enable) 123 return clk->enable(clk); 124 125 return -1; 126 } 127 EXPORT_SYMBOL(clk_enable); 128 129 void clk_disable(struct clk *clk) 130 { 131 if (unlikely(!clk_good(clk))) 132 return; 133 134 if (clk->disable) 135 clk->disable(clk); 136 } 137 EXPORT_SYMBOL(clk_disable); 138 139 int clk_activate(struct clk *clk) 140 { 141 if (unlikely(!clk_good(clk))) 142 return -1; 143 144 if (clk->activate) 145 return clk->activate(clk); 146 147 return -1; 148 } 149 EXPORT_SYMBOL(clk_activate); 150 151 void clk_deactivate(struct clk *clk) 152 { 153 if (unlikely(!clk_good(clk))) 154 return; 155 156 if (clk->deactivate) 157 clk->deactivate(clk); 158 } 159 EXPORT_SYMBOL(clk_deactivate); 160 161 static inline u32 get_counter_resolution(void) 162 { 163 u32 res; 164 165 __asm__ __volatile__( 166 ".set push\n" 167 ".set mips32r2\n" 168 "rdhwr %0, $3\n" 169 ".set pop\n" 170 : "=&r" (res) 171 : /* no input */ 172 : "memory"); 173 174 return res; 175 } 176 177 void __init plat_time_init(void) 178 { 179 struct clk *clk; 180 181 ltq_soc_init(); 182 183 clk = clk_get_cpu(); 184 mips_hpt_frequency = clk_get_rate(clk) / get_counter_resolution(); 185 write_c0_compare(read_c0_count()); 186 pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000); 187 clk_put(clk); 188 } 189