Commit | Line | Data |
---|---|---|
6fa3eb70 S |
1 | /* |
2 | * Copyright (C) 2011 MediaTek, Inc. | |
3 | * | |
4 | * Author: Holmes Chiou <holmes.chiou@mediatek.com> | |
5 | * | |
6 | * This software is licensed under the terms of the GNU General Public | |
7 | * License version 2, as published by the Free Software Foundation, and | |
8 | * may be copied, distributed, and modified under those terms. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | */ | |
16 | #include <linux/module.h> | |
17 | #include <linux/kernel.h> | |
18 | #include <linux/sched.h> | |
19 | #include <linux/kthread.h> | |
20 | #include <linux/delay.h> | |
21 | #include <linux/uaccess.h> | |
22 | #include <linux/io.h> | |
23 | #include <linux/platform_device.h> | |
24 | #include <linux/miscdevice.h> | |
25 | //#include <asm/sched_clock.h> | |
26 | #include <linux/vmalloc.h> | |
27 | #include <linux/dma-mapping.h> | |
28 | #include <board-custom.h> | |
29 | #include <linux/seq_file.h> | |
30 | ||
31 | #include "mach/mt_fhreg.h" | |
32 | ||
33 | #include <linux/xlog.h> //ccyeh: for 6572 | |
34 | ||
35 | #if 0 //ccyeh: we don't need these header files here. | |
36 | #include "mach/mt_clkmgr.h" | |
37 | #include "mach/mt_typedefs.h" | |
38 | #include "mach/mt_gpio.h" | |
39 | #include "mach/mt_gpufreq.h" | |
40 | #include "mach/mt_cpufreq.h" | |
41 | #include "mach/emi_bwl.h" | |
42 | #include "mach/sync_write.h" | |
43 | #include "mach/mt_sleep.h" | |
44 | #endif | |
45 | ||
46 | #include <mach/mt_freqhopping_drv.h> | |
47 | ||
48 | ||
49 | #define FREQ_HOPPING_DEVICE "mt-freqhopping" | |
50 | ||
51 | #define FH_PLL_COUNT (g_p_fh_hal_drv->pll_cnt) | |
52 | ||
53 | //static unsigned int g_resume_mempll_ssc=false; | |
54 | static struct mt_fh_hal_driver *g_p_fh_hal_drv; | |
55 | ||
56 | static fh_pll_t *g_fh_drv_pll; | |
57 | static struct freqhopping_ssc *g_fh_drv_usr_def; | |
58 | static unsigned int g_drv_pll_count; | |
59 | ||
60 | static struct miscdevice mt_fh_device = { | |
61 | .minor = MISC_DYNAMIC_MINOR, | |
62 | .name = "mtfreqhopping", | |
63 | //.fops = &mt_fh_fops, //TODO: Interface for UI maybe in the future... | |
64 | }; | |
65 | ||
66 | ||
67 | static int mt_freqhopping_ioctl(struct file *file, unsigned int cmd, unsigned long arg); | |
68 | ||
69 | static int mt_fh_drv_probe(struct platform_device *dev) | |
70 | { | |
71 | int err = 0; | |
72 | ||
73 | FH_MSG("EN: mt_fh_probe()"); | |
74 | ||
75 | if ((err = misc_register(&mt_fh_device))) | |
76 | FH_MSG("register fh driver error!"); | |
77 | ||
78 | return err; | |
79 | } | |
80 | ||
81 | static int mt_fh_drv_remove(struct platform_device *dev) | |
82 | { | |
83 | int err = 0; | |
84 | ||
85 | if ((err = misc_deregister(&mt_fh_device))) | |
86 | FH_MSG("deregister fh driver error!"); | |
87 | ||
88 | return err; | |
89 | } | |
90 | ||
91 | static void mt_fh_drv_shutdown(struct platform_device *dev) | |
92 | { | |
93 | FH_MSG("mt_fh_shutdown"); | |
94 | } | |
95 | ||
96 | static int mt_fh_drv_suspend(struct platform_device *dev, pm_message_t state) | |
97 | { | |
98 | // struct freqhopping_ioctl fh_ctl; | |
99 | ||
100 | FH_MSG("-supd-"); | |
101 | ||
102 | return 0; | |
103 | } | |
104 | ||
105 | static int mt_fh_drv_resume(struct platform_device *dev) | |
106 | { | |
107 | // struct freqhopping_ioctl fh_ctl; | |
108 | ||
109 | FH_MSG("+resm+"); | |
110 | ||
111 | return 0; | |
112 | } | |
113 | ||
114 | static struct platform_driver freqhopping_driver = { | |
115 | .probe = mt_fh_drv_probe, | |
116 | .remove = mt_fh_drv_remove, | |
117 | .shutdown = mt_fh_drv_shutdown, | |
118 | .suspend = mt_fh_drv_suspend, | |
119 | .resume = mt_fh_drv_resume, | |
120 | .driver = { | |
121 | .name = FREQ_HOPPING_DEVICE, | |
122 | .owner = THIS_MODULE, | |
123 | }, | |
124 | }; | |
125 | ||
126 | static int mt_fh_enable_usrdef(struct freqhopping_ioctl* fh_ctl) | |
127 | { | |
128 | unsigned long flags = 0; | |
129 | const unsigned int pll_id = fh_ctl->pll_id; | |
130 | ||
131 | FH_MSG("EN: %s",__func__); | |
132 | FH_MSG("pll_id: %d",fh_ctl->pll_id); | |
133 | ||
134 | if (fh_ctl->pll_id < FH_PLL_COUNT){ | |
135 | //we don't care the PLL status , we just change the flag & update the table | |
136 | //the setting will be applied during the following FH enable | |
137 | ||
138 | g_p_fh_hal_drv->mt_fh_lock(&flags); | |
139 | memcpy(&g_fh_drv_usr_def[pll_id],&(fh_ctl->ssc_setting),sizeof(g_fh_drv_usr_def[pll_id])); | |
140 | g_fh_drv_pll[pll_id].user_defined = true; | |
141 | g_p_fh_hal_drv->mt_fh_unlock(&flags); | |
142 | } | |
143 | ||
144 | //FH_MSG("Exit"); | |
145 | ||
146 | return 0; | |
147 | ||
148 | } | |
149 | ||
150 | static int mt_fh_disable_usrdef(struct freqhopping_ioctl* fh_ctl) | |
151 | { | |
152 | unsigned long flags = 0; | |
153 | const unsigned int pll_id = fh_ctl->pll_id; | |
154 | ||
155 | FH_MSG("EN: %s",__func__); | |
156 | FH_MSG("id: %d",fh_ctl->pll_id); | |
157 | ||
158 | if (fh_ctl->pll_id < FH_PLL_COUNT){ | |
159 | g_p_fh_hal_drv->mt_fh_lock(&flags); | |
160 | memset(&g_fh_drv_usr_def[pll_id], 0,sizeof(g_fh_drv_usr_def[pll_id])); | |
161 | g_fh_drv_pll[pll_id].user_defined = false; | |
162 | g_p_fh_hal_drv->mt_fh_unlock(&flags); | |
163 | } | |
164 | ||
165 | //FH_MSG("Exit"); | |
166 | ||
167 | return 0; | |
168 | } | |
169 | ||
170 | static int mt_fh_hal_ctrl_lock(struct freqhopping_ioctl* fh_ctl,bool enable) | |
171 | { | |
172 | int retVal=1; | |
173 | unsigned long flags = 0; | |
174 | ||
175 | FH_MSG("EN: _fctr_lck %d:%d",fh_ctl->pll_id,enable); | |
176 | ||
177 | g_p_fh_hal_drv->mt_fh_lock(&flags); | |
178 | retVal = g_p_fh_hal_drv->mt_fh_hal_ctrl(fh_ctl, enable); | |
179 | g_p_fh_hal_drv->mt_fh_unlock(&flags); | |
180 | ||
181 | return retVal; | |
182 | } | |
183 | ||
184 | ||
185 | static int mt_freqhopping_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |
186 | { | |
187 | //Get the structure of ioctl | |
188 | int ret = 0; | |
189 | ||
190 | struct freqhopping_ioctl *freqhopping_ctl = (struct freqhopping_ioctl *)arg; | |
191 | ||
192 | FH_MSG("EN:CMD:%d pll id:%d",cmd,freqhopping_ctl->pll_id); | |
193 | ||
194 | if(FH_CMD_ENABLE == cmd) { | |
195 | ret = mt_fh_hal_ctrl_lock(freqhopping_ctl,true); | |
196 | }else if(FH_CMD_DISABLE == cmd) { | |
197 | ret = mt_fh_hal_ctrl_lock(freqhopping_ctl,false); | |
198 | } | |
199 | else if(FH_CMD_ENABLE_USR_DEFINED == cmd) { | |
200 | ret = mt_fh_enable_usrdef(freqhopping_ctl); | |
201 | } | |
202 | else if(FH_CMD_DISABLE_USR_DEFINED == cmd) { | |
203 | ret = mt_fh_disable_usrdef(freqhopping_ctl); | |
204 | }else { | |
205 | //Invalid command is not acceptable!! | |
206 | WARN_ON(1); | |
207 | } | |
208 | ||
209 | //FH_MSG("Exit"); | |
210 | ||
211 | return ret; | |
212 | } | |
213 | ||
214 | //static int freqhopping_userdefine_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) | |
215 | static int freqhopping_userdefine_proc_read(struct seq_file* m, void* v) | |
216 | { | |
217 | int i=0; | |
218 | ||
219 | FH_MSG("EN: %s",__func__); | |
220 | ||
221 | seq_printf(m, "user defined settings:\n"); | |
222 | ||
223 | seq_printf(m, "===============================================\r\n" ); | |
224 | seq_printf(m, " freq == delta t == delta f == up bond == low bond == dds ==\r\n" ); | |
225 | ||
226 | for(i = 0;i < g_drv_pll_count ; ++i) { | |
227 | seq_printf(m, "%10d 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\r\n" | |
228 | ,g_fh_drv_usr_def[i].freq | |
229 | ,g_fh_drv_usr_def[i].dt | |
230 | ,g_fh_drv_usr_def[i].df | |
231 | ,g_fh_drv_usr_def[i].upbnd | |
232 | ,g_fh_drv_usr_def[i].lowbnd | |
233 | ,g_fh_drv_usr_def[i].dds); | |
234 | } | |
235 | ||
236 | return 0; | |
237 | ||
238 | #if 0 | |
239 | char *p = page; | |
240 | int len = 0; | |
241 | int i=0; | |
242 | ||
243 | FH_MSG("EN: %s",__func__); | |
244 | ||
245 | p += sprintf(p, "user defined settings:\n"); | |
246 | ||
247 | p += sprintf(p, "===============================================\r\n" ); | |
248 | p += sprintf(p, " freq == delta t == delta f == up bond == low bond == dds ==\r\n" ); | |
249 | ||
250 | for(i=0;i<g_drv_pll_count ;i++) { | |
251 | p += sprintf(p, "%10d 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\r\n" | |
252 | ,g_fh_drv_usr_def[i].freq | |
253 | ,g_fh_drv_usr_def[i].dt | |
254 | ,g_fh_drv_usr_def[i].df | |
255 | ,g_fh_drv_usr_def[i].upbnd | |
256 | ,g_fh_drv_usr_def[i].lowbnd | |
257 | ,g_fh_drv_usr_def[i].dds); | |
258 | } | |
259 | ||
260 | *start = page + off; | |
261 | ||
262 | len = p - page; | |
263 | ||
264 | if (len > off) | |
265 | len -= off; | |
266 | else | |
267 | len = 0; | |
268 | ||
269 | return len < count ? len : count; | |
270 | #endif | |
271 | } | |
272 | ||
273 | static ssize_t freqhopping_userdefine_proc_write(struct file *file, const char *buffer, size_t count, loff_t *data) | |
274 | { | |
275 | int ret; | |
276 | char kbuf[256]; | |
277 | size_t len = 0; | |
278 | unsigned int p1,p2,p3,p4,p5,p6,p7; | |
279 | struct freqhopping_ioctl fh_ctl; | |
280 | ||
281 | p1 = p2 = p3 = p4 = p5 = p6 = p7 = 0; | |
282 | ||
283 | FH_MSG("EN: %s",__func__); | |
284 | ||
285 | len = min(count, (sizeof(kbuf)-1)); | |
286 | ||
287 | if (count == 0)return -1; | |
288 | if(count > 255)count = 255; | |
289 | ||
290 | ret = copy_from_user(kbuf, buffer, count); | |
291 | if (ret < 0)return -1; | |
292 | ||
293 | kbuf[count] = '\0'; | |
294 | ||
295 | sscanf(kbuf, "%x %x %x %x %x %x %x", &p1, &p2, &p3, &p4, &p5, &p6, &p7); | |
296 | ||
297 | fh_ctl.pll_id = p2; | |
298 | fh_ctl.ssc_setting.df = p3; | |
299 | fh_ctl.ssc_setting.dt = p4; | |
300 | fh_ctl.ssc_setting.upbnd = p5; | |
301 | fh_ctl.ssc_setting.lowbnd = p6; | |
302 | fh_ctl.ssc_setting.dds = p7; | |
303 | fh_ctl.ssc_setting.freq = 0; | |
304 | ||
4b9e9796 S |
305 | /* Check validity of PLL ID */ |
306 | if (fh_ctl.pll_id >= FH_PLL_COUNT) | |
307 | return -1; | |
308 | ||
6fa3eb70 S |
309 | |
310 | if( p1 == FH_CMD_ENABLE){ | |
311 | ret = mt_fh_enable_usrdef(&fh_ctl); | |
312 | if(ret){ | |
313 | FH_MSG("__EnableUsrSetting() fail!"); | |
314 | } | |
315 | } | |
316 | else{ | |
317 | ret = mt_fh_disable_usrdef(&fh_ctl); | |
318 | if(ret){ | |
319 | FH_MSG("__DisableUsrSetting() fail!"); | |
320 | } | |
321 | } | |
322 | ||
323 | FH_MSG("Exit: %s",__func__); | |
324 | return count; | |
325 | } | |
326 | ||
327 | //static int freqhopping_status_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) | |
328 | static int freqhopping_status_proc_read(struct seq_file* m, void* v) | |
329 | { | |
330 | int i=0; | |
331 | ||
332 | FH_MSG("EN: %s",__func__); | |
333 | ||
334 | seq_printf(m, "FH status:\r\n"); | |
335 | ||
336 | seq_printf(m, "===============================================\r\n" ); | |
337 | seq_printf(m, "id == fh_status == pll_status == setting_id == curr_freq == user_defined ==\r\n" ); | |
338 | ||
339 | ||
340 | for(i = 0;i < g_drv_pll_count ; ++i) { | |
341 | seq_printf(m, "%2d %8d %8d", | |
342 | i, | |
343 | g_fh_drv_pll[i].fh_status, | |
344 | g_fh_drv_pll[i].pll_status); | |
345 | seq_printf(m, " %8d %8d ", | |
346 | g_fh_drv_pll[i].setting_id, | |
347 | g_fh_drv_pll[i].curr_freq); | |
348 | ||
349 | seq_printf(m, " %d\r\n", | |
350 | g_fh_drv_pll[i].user_defined); | |
351 | } | |
352 | seq_printf(m, "\r\n"); | |
353 | ||
354 | return 0; | |
355 | ||
356 | #if 0 | |
357 | char *p = page; | |
358 | int len = 0; | |
359 | int i=0; | |
360 | ||
361 | FH_MSG("EN: %s",__func__); | |
362 | ||
363 | p += sprintf(p, "FH status:\r\n"); | |
364 | ||
365 | p += sprintf(p, "===============================================\r\n" ); | |
366 | p += sprintf(p, "id == fh_status == pll_status == setting_id == curr_freq == user_defined ==\r\n" ); | |
367 | ||
368 | ||
369 | for(i=0;i<g_drv_pll_count ;i++) { | |
370 | p += sprintf(p, "%2d %8d %8d", | |
371 | i, | |
372 | g_fh_drv_pll[i].fh_status, | |
373 | g_fh_drv_pll[i].pll_status); | |
374 | p += sprintf(p, " %8d %8d ", | |
375 | g_fh_drv_pll[i].setting_id, | |
376 | g_fh_drv_pll[i].curr_freq); | |
377 | ||
378 | p += sprintf(p, " %d\r\n", | |
379 | g_fh_drv_pll[i].user_defined); | |
380 | } | |
381 | #if 0 | |
382 | p += sprintf(p, "\r\nPLL status:\r\n"); | |
383 | for(i=0;i<g_drv_pll_count ;i++) { | |
384 | p += sprintf(p, "%d ",pll_is_on(i)); | |
385 | } | |
386 | #endif | |
387 | p += sprintf(p, "\r\n"); | |
388 | ||
389 | //TODO: unsigned int mt_get_cpu_freq(void) | |
390 | ||
391 | ||
392 | *start = page + off; | |
393 | ||
394 | len = p - page; | |
395 | ||
396 | if (len > off) | |
397 | len -= off; | |
398 | else | |
399 | len = 0; | |
400 | ||
401 | return len < count ? len : count; | |
402 | #endif | |
403 | } | |
404 | ||
405 | static ssize_t freqhopping_status_proc_write(struct file *file, const char *buffer, size_t count, loff_t *data) | |
406 | { | |
407 | int ret; | |
408 | char kbuf[256]; | |
409 | size_t len = 0; | |
410 | unsigned int p1,p2,p3,p4,p5,p6; | |
411 | struct freqhopping_ioctl fh_ctl; | |
412 | ||
413 | p1 = p2 = p3 = p4 = p5 = p6 = 0; | |
414 | ||
415 | FH_MSG("EN: %s",__func__); | |
416 | ||
417 | len = min(count, (sizeof(kbuf)-1)); | |
418 | ||
419 | if (count == 0)return -1; | |
420 | if(count > 255)count = 255; | |
421 | ||
422 | ret = copy_from_user(kbuf, buffer, count); | |
423 | if (ret < 0)return -1; | |
424 | ||
425 | kbuf[count] = '\0'; | |
426 | ||
427 | sscanf(kbuf, "%x %x", &p1, &p2); | |
428 | ||
429 | fh_ctl.pll_id = p2; | |
430 | fh_ctl.ssc_setting.df= 0; | |
431 | fh_ctl.ssc_setting.dt= 0; | |
432 | fh_ctl.ssc_setting.upbnd= 0; | |
433 | fh_ctl.ssc_setting.lowbnd= 0; | |
434 | ||
4b9e9796 S |
435 | /* Check validity of PLL ID */ |
436 | if (fh_ctl.pll_id >= FH_PLL_COUNT) | |
437 | return -1; | |
438 | ||
6fa3eb70 S |
439 | if( p1 == 0){ |
440 | mt_freqhopping_ioctl(NULL,FH_CMD_DISABLE,(unsigned long)(&fh_ctl)); | |
441 | } | |
442 | else{ | |
443 | mt_freqhopping_ioctl(NULL,FH_CMD_ENABLE,(unsigned long)(&fh_ctl)); | |
444 | } | |
445 | ||
446 | return count; | |
447 | } | |
448 | ||
449 | //static int freqhopping_debug_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) | |
450 | static int freqhopping_debug_proc_read(struct seq_file* m, void* v) | |
451 | { | |
452 | #if defined(PLATFORM_DEP_DEBUG_PROC_READ) | |
453 | FH_IO_PROC_READ_T arg; | |
454 | arg.m = m; | |
455 | arg.v = v; | |
456 | arg.pll = g_fh_drv_pll; | |
4b9e9796 | 457 | //g_p_fh_hal_drv->ioctl(FH_IO_PROC_READ, &arg); |
6fa3eb70 S |
458 | return 0; |
459 | #else | |
460 | FH_MSG("EN: %s",__func__); | |
461 | ||
462 | seq_printf(m, "\r\n[freqhopping debug flag]\r\n"); | |
463 | seq_printf(m, "===============================================\r\n" ); | |
464 | seq_printf(m, "id==ARMPLL==MAINPLL==MEMPLL==MSDCPLL==MMPLL==VENCPLL\r\n" ); | |
465 | seq_printf(m, " == %04d====%04d====%04d====%04d====%04d====%04d=\r\n" , | |
466 | g_fh_drv_pll[MT658X_FH_ARM_PLL].fh_status, g_fh_drv_pll[MT658X_FH_MAIN_PLL].fh_status, | |
467 | g_fh_drv_pll[MT658X_FH_MEM_PLL].fh_status, g_fh_drv_pll[MT658X_FH_MSDC_PLL].fh_status, | |
468 | g_fh_drv_pll[MT658X_FH_MM_PLL].fh_status, g_fh_drv_pll[MT658X_FH_VENC_PLL].fh_status); | |
469 | seq_printf(m, " == %04d====%04d====%04d====%04d====%04d====%04d=\r\n" , | |
470 | g_fh_drv_pll[MT658X_FH_ARM_PLL].setting_id, g_fh_drv_pll[MT658X_FH_MAIN_PLL].setting_id, | |
471 | g_fh_drv_pll[MT658X_FH_MEM_PLL].setting_id, g_fh_drv_pll[MT658X_FH_MSDC_PLL].setting_id, | |
472 | g_fh_drv_pll[MT658X_FH_MM_PLL].setting_id, g_fh_drv_pll[MT658X_FH_VENC_PLL].setting_id); | |
473 | return 0; | |
474 | #if 0 | |
475 | char *p = page; | |
476 | int len = 0; | |
477 | ||
478 | FH_MSG("EN: %s",__func__); | |
479 | ||
480 | p += sprintf(p, "\r\n[freqhopping debug flag]\r\n"); | |
481 | p += sprintf(p, "===============================================\r\n" ); | |
482 | p += sprintf(p, "id==ARMPLL==MAINPLL==MEMPLL==MSDCPLL==MMPLL==VENCPLL\r\n" ); | |
483 | p += sprintf(p, " == %04d====%04d====%04d====%04d====%04d====%04d=\r\n" , | |
484 | g_fh_drv_pll[MT658X_FH_ARM_PLL].fh_status, g_fh_drv_pll[MT658X_FH_MAIN_PLL].fh_status, | |
485 | g_fh_drv_pll[MT658X_FH_MEM_PLL].fh_status, g_fh_drv_pll[MT658X_FH_MSDC_PLL].fh_status, | |
486 | g_fh_drv_pll[MT658X_FH_MM_PLL].fh_status, g_fh_drv_pll[MT658X_FH_VENC_PLL].fh_status); | |
487 | p += sprintf(p, " == %04d====%04d====%04d====%04d====%04d====%04d=\r\n" , | |
488 | g_fh_drv_pll[MT658X_FH_ARM_PLL].setting_id, g_fh_drv_pll[MT658X_FH_MAIN_PLL].setting_id, | |
489 | g_fh_drv_pll[MT658X_FH_MEM_PLL].setting_id, g_fh_drv_pll[MT658X_FH_MSDC_PLL].setting_id, | |
490 | g_fh_drv_pll[MT658X_FH_MM_PLL].setting_id, g_fh_drv_pll[MT658X_FH_VENC_PLL].setting_id); | |
491 | ||
492 | *start = page + off; | |
493 | ||
494 | len = p - page; | |
495 | ||
496 | if (len > off) | |
497 | len -= off; | |
498 | else | |
499 | len = 0; | |
500 | ||
501 | return len < count ? len : count; | |
502 | #endif | |
503 | #endif | |
504 | } | |
505 | ||
506 | static ssize_t freqhopping_debug_proc_write(struct file *file, const char *buffer, size_t count, loff_t *data) | |
507 | { | |
508 | int ret; | |
509 | char kbuf[256]; | |
510 | size_t len = 0; | |
511 | unsigned int cmd,p1,p2,p3,p4,p5,p6,p7; | |
512 | struct freqhopping_ioctl fh_ctl; | |
513 | ||
514 | p1 = p2 = p3 = p4 = p5 = p6 = p7 = 0; | |
515 | ||
516 | FH_MSG("EN: %s",__func__); | |
517 | ||
518 | len = min(count, (sizeof(kbuf)-1)); | |
519 | ||
520 | if (count == 0)return -1; | |
521 | if(count > 255)count = 255; | |
522 | ||
523 | ret = copy_from_user(kbuf, buffer, count); | |
524 | if (ret < 0)return -1; | |
525 | ||
526 | kbuf[count] = '\0'; | |
527 | ||
528 | sscanf(kbuf, "%x %x %x %x %x %x %x %x", &cmd, &p1, &p2, &p3, &p4, &p5, &p6, &p7); | |
529 | ||
530 | //ccyeh fh_ctl.opcode = p1; | |
531 | fh_ctl.pll_id = p2; | |
532 | //ccyeh removed fh_ctl.ssc_setting_id = p3; | |
533 | fh_ctl.ssc_setting.dds = p3; | |
534 | fh_ctl.ssc_setting.df = p4; | |
535 | fh_ctl.ssc_setting.dt = p5; | |
536 | fh_ctl.ssc_setting.upbnd = p6; | |
537 | fh_ctl.ssc_setting.lowbnd = p7; | |
538 | fh_ctl.ssc_setting.freq = 0; | |
539 | ||
4b9e9796 S |
540 | /* Check validity of PLL ID */ |
541 | if (fh_ctl.pll_id >= FH_PLL_COUNT) | |
542 | return -1; | |
543 | ||
6fa3eb70 S |
544 | |
545 | if (cmd < FH_CMD_INTERNAL_MAX_CMD) { | |
546 | mt_freqhopping_ioctl(NULL,cmd,(unsigned long)(&fh_ctl)); | |
547 | } | |
548 | else if((cmd > FH_DCTL_CMD_ID) && (cmd < FH_DCTL_CMD_MAX)) | |
549 | { | |
550 | mt_freqhopping_devctl(cmd, &fh_ctl); | |
551 | } | |
552 | else { | |
553 | FH_MSG("CMD error!"); | |
554 | } | |
555 | ||
556 | return count; | |
557 | } | |
558 | ||
559 | static int freqhopping_debug_proc_open(struct inode *inode, struct file *file) | |
560 | { | |
561 | return single_open(file, freqhopping_debug_proc_read, NULL); | |
562 | } | |
563 | ||
564 | static int freqhopping_dramc_proc_open(struct inode *inode, struct file *file) | |
565 | { | |
566 | return single_open(file, g_p_fh_hal_drv->proc.dramc_read, NULL); | |
567 | } | |
568 | static ssize_t freqhopping_dramc_proc_write(struct file *file, const char *buffer, size_t count, loff_t *data) | |
569 | { | |
570 | return (ssize_t)(g_p_fh_hal_drv->proc.dramc_write(file, buffer, count, data)); | |
571 | } | |
572 | ||
573 | static int freqhopping_dvfs_proc_open(struct inode *inode, struct file *file) | |
574 | { | |
575 | return single_open(file, g_p_fh_hal_drv->proc.dvfs_read, NULL); | |
576 | } | |
577 | static ssize_t freqhopping_dvfs_proc_write(struct file *file, const char *buffer, size_t count, loff_t *data) | |
578 | { | |
579 | return (ssize_t)(g_p_fh_hal_drv->proc.dvfs_write(file, buffer, count, data)); | |
580 | } | |
581 | ||
582 | static int freqhopping_dumpregs_proc_open(struct inode *inode, struct file *file) | |
583 | { | |
584 | return single_open(file, g_p_fh_hal_drv->proc.dumpregs_read, NULL); | |
585 | } | |
586 | ||
587 | static int freqhopping_status_proc_open(struct inode *inode, struct file *file) | |
588 | { | |
589 | return single_open(file, freqhopping_status_proc_read, NULL); | |
590 | } | |
591 | static int freqhopping_userdefine_proc_open(struct inode *inode, struct file *file) | |
592 | { | |
593 | return single_open(file, freqhopping_userdefine_proc_read, NULL); | |
594 | } | |
595 | ||
596 | static const struct file_operations freqhopping_debug_fops = { | |
597 | .owner = THIS_MODULE, | |
598 | .open = freqhopping_debug_proc_open, | |
599 | .read = seq_read, | |
600 | .write = freqhopping_debug_proc_write, | |
601 | }; | |
602 | static const struct file_operations dramc_fops = { | |
603 | .owner = THIS_MODULE, | |
604 | .open = freqhopping_dramc_proc_open, | |
605 | .read = seq_read, | |
606 | .write = freqhopping_dramc_proc_write, | |
607 | }; | |
608 | static const struct file_operations dvfs_fops = { | |
609 | .owner = THIS_MODULE, | |
610 | .open = freqhopping_dvfs_proc_open, | |
611 | .read = seq_read, | |
612 | .write = freqhopping_dvfs_proc_write, | |
613 | }; | |
614 | static const struct file_operations dumpregs_fops = { | |
615 | .owner = THIS_MODULE, | |
616 | .open = freqhopping_dumpregs_proc_open, | |
617 | .read = seq_read, | |
618 | }; | |
619 | static const struct file_operations status_fops = { | |
620 | .owner = THIS_MODULE, | |
621 | .open = freqhopping_status_proc_open, | |
622 | .read = seq_read, | |
623 | .write = freqhopping_status_proc_write, | |
624 | }; | |
625 | static const struct file_operations userdef_fops = { | |
626 | .owner = THIS_MODULE, | |
627 | .open = freqhopping_userdefine_proc_open, | |
628 | .read = seq_read, | |
629 | .write = freqhopping_userdefine_proc_write, | |
630 | }; | |
631 | ||
632 | static int freqhopping_debug_proc_init(void) | |
633 | { | |
634 | struct proc_dir_entry *prDebugEntry; | |
635 | struct proc_dir_entry *prDramcEntry; | |
636 | struct proc_dir_entry *prDumpregEntry; | |
637 | struct proc_dir_entry *prStatusEntry; | |
638 | struct proc_dir_entry *prUserdefEntry; | |
639 | struct proc_dir_entry *fh_proc_dir = NULL; | |
640 | ||
641 | //TODO: check the permission!! | |
642 | ||
643 | FH_MSG("EN: %s",__func__); | |
644 | ||
645 | fh_proc_dir = proc_mkdir("freqhopping", NULL); | |
646 | if (!fh_proc_dir){ | |
647 | FH_MSG("proc_mkdir fail!"); | |
648 | return 1; | |
649 | } | |
650 | else{ | |
651 | ||
652 | ||
653 | /* /proc/freqhopping/freqhopping_debug */ | |
654 | //prDebugEntry = create_proc_entry("freqhopping_debug", S_IRUGO | S_IWUSR | S_IWGRP, fh_proc_dir); | |
655 | prDebugEntry = proc_create("freqhopping_debug", S_IRUGO | S_IWUSR | S_IWGRP, fh_proc_dir, &freqhopping_debug_fops); | |
656 | if(prDebugEntry) | |
657 | { | |
658 | //prDebugEntry->read_proc = freqhopping_debug_proc_read; | |
659 | //prDebugEntry->write_proc = freqhopping_debug_proc_write; | |
660 | FH_MSG("[%s]: successfully create /proc/freqhopping_debug", __func__); | |
661 | }else{ | |
662 | FH_MSG("[%s]: failed to create /proc/freqhopping/freqhopping_debug", __func__); | |
663 | return 1; | |
664 | } | |
665 | ||
666 | ||
667 | /* /proc/freqhopping/dramc */ | |
668 | //prDramcEntry = create_proc_entry("dramc", S_IRUGO | S_IWUSR | S_IWGRP, fh_proc_dir); | |
669 | prDramcEntry = proc_create("dramc", S_IRUGO | S_IWUSR | S_IWGRP, fh_proc_dir, &dramc_fops); | |
670 | if(prDramcEntry) | |
671 | { | |
672 | //prDramcEntry->read_proc = g_p_fh_hal_drv->proc.dramc_read; | |
673 | //prDramcEntry->write_proc = g_p_fh_hal_drv->proc.dramc_write; | |
674 | FH_MSG("[%s]: successfully create /proc/freqhopping/prDramcEntry", __func__); | |
675 | }else{ | |
676 | FH_MSG("[%s]: failed to create /proc/freqhopping/prDramcEntry", __func__); | |
677 | return 1; | |
678 | } | |
679 | /* /proc/freqhopping/dvfs */ | |
680 | //prDramcEntry = create_proc_entry("dvfs", S_IRUGO | S_IWUSR | S_IWGRP, fh_proc_dir); | |
681 | prDramcEntry = proc_create("dvfs", S_IRUGO | S_IWUSR | S_IWGRP, fh_proc_dir, &dvfs_fops); | |
682 | if(prDramcEntry) | |
683 | { | |
684 | //prDramcEntry->read_proc = g_p_fh_hal_drv->proc.dvfs_read; | |
685 | //prDramcEntry->write_proc = g_p_fh_hal_drv->proc.dvfs_write; | |
686 | FH_MSG("[%s]: successfully create /proc/freqhopping/dvfs", __func__); | |
687 | }else{ | |
688 | FH_MSG("[%s]: failed to create /proc/freqhopping/dvfs", __func__); | |
689 | return 1; | |
690 | } | |
691 | ||
692 | ||
693 | /* /proc/freqhopping/dumpregs */ | |
694 | //prDumpregEntry = create_proc_entry("dumpregs", S_IRUGO | S_IWUSR | S_IWGRP, fh_proc_dir); | |
695 | prDumpregEntry = proc_create("dumpregs", S_IRUGO | S_IWUSR | S_IWGRP, fh_proc_dir, &dumpregs_fops); | |
696 | if(prDumpregEntry) | |
697 | { | |
698 | //prDumpregEntry->read_proc = g_p_fh_hal_drv->proc.dumpregs_read; | |
699 | //prDumpregEntry->write_proc = NULL; | |
700 | FH_MSG("[%s]: successfully create /proc/freqhopping/dumpregs", __func__); | |
701 | }else{ | |
702 | FH_MSG("[%s]: failed to create /proc/freqhopping/dumpregs", __func__); | |
703 | return 1; | |
704 | } | |
705 | ||
706 | ||
707 | /* /proc/freqhopping/status */ | |
708 | //prStatusEntry = create_proc_entry("status", S_IRUGO | S_IWUSR | S_IWGRP, fh_proc_dir); | |
709 | prStatusEntry = proc_create("status", S_IRUGO | S_IWUSR | S_IWGRP, fh_proc_dir, &status_fops); | |
710 | if(prStatusEntry) | |
711 | { | |
712 | //prStatusEntry->read_proc = freqhopping_status_proc_read; | |
713 | //prStatusEntry->write_proc = freqhopping_status_proc_write; | |
714 | FH_MSG("[%s]: successfully create /proc/freqhopping/status", __func__); | |
715 | }else{ | |
716 | FH_MSG("[%s]: failed to create /proc/freqhopping/status", __func__); | |
717 | return 1; | |
718 | } | |
719 | ||
720 | ||
721 | /* /proc/freqhopping/userdefine */ | |
722 | //prUserdefEntry = create_proc_entry("userdef", S_IRUGO | S_IWUSR | S_IWGRP, fh_proc_dir); | |
723 | prUserdefEntry = proc_create("userdef", S_IRUGO | S_IWUSR | S_IWGRP, fh_proc_dir, &userdef_fops); | |
724 | if(prUserdefEntry) | |
725 | { | |
726 | //prUserdefEntry->read_proc = freqhopping_userdefine_proc_read; | |
727 | //prUserdefEntry->write_proc = freqhopping_userdefine_proc_write; | |
728 | FH_MSG("[%s]: successfully create /proc/freqhopping/userdef", __func__); | |
729 | }else{ | |
730 | FH_MSG("[%s]: failed to create /proc/freqhopping/userdef", __func__); | |
731 | return 1; | |
732 | } | |
733 | ||
734 | #if 0// MT_FH_CLK_GEN | |
735 | /* /proc/freqhopping/clkgen */ | |
736 | prUserdefEntry = create_proc_entry("clkgen", S_IRUGO | S_IWUSR | S_IWGRP, fh_proc_dir); | |
737 | if(prUserdefEntry) | |
738 | { | |
739 | prUserdefEntry->read_proc = g_p_fh_hal_drv->proc.clk_gen_read; | |
740 | prUserdefEntry->write_proc = g_p_fh_hal_drv->proc.clk_gen_write; | |
741 | FH_MSG("[%s]: successfully create /proc/freqhopping/clkgen", __func__); | |
742 | }else{ | |
743 | FH_MSG("[%s]: failed to create /proc/freqhopping/clkgen", __func__); | |
744 | return 1; | |
745 | } | |
746 | #endif //MT_FH_CLK_GEN | |
747 | } | |
748 | ||
749 | return 0 ; | |
750 | } | |
751 | ||
752 | #if defined(DISABLE_FREQ_HOPPING) | |
753 | void mt_fh_popod_save(void){} | |
754 | EXPORT_SYMBOL(mt_fh_popod_save); | |
755 | ||
756 | void mt_fh_popod_restore(void){} | |
757 | EXPORT_SYMBOL(mt_fh_popod_restore); | |
758 | ||
759 | int freqhopping_config(unsigned int pll_id, unsigned long vco_freq, unsigned int enable){return 0;} | |
760 | EXPORT_SYMBOL(freqhopping_config); | |
761 | ||
762 | int mt_l2h_mempll(void){return 0;} | |
763 | EXPORT_SYMBOL(mt_l2h_mempll); | |
764 | ||
765 | int mt_h2l_mempll(void){return 0;} | |
766 | EXPORT_SYMBOL(mt_h2l_mempll); | |
767 | ||
768 | int mt_dfs_armpll(unsigned int current_freq, unsigned int target_dds){return 0;} | |
769 | EXPORT_SYMBOL(mt_dfs_armpll); | |
770 | ||
771 | int mt_dfs_mmpll(unsigned int target_dds){ return 0;} | |
772 | EXPORT_SYMBOL(mt_dfs_mmpll); | |
773 | ||
774 | int mt_dfs_vencpll(unsigned int target_dds){return 0;} | |
775 | EXPORT_SYMBOL(mt_dfs_vencpll); | |
776 | ||
777 | int mt_dfs_mpll(unsigned int target_dds){return 0;} | |
778 | EXPORT_SYMBOL(mt_dfs_mpll); | |
779 | ||
780 | int mt_is_support_DFS_mode(void){return 0;} | |
781 | EXPORT_SYMBOL(mt_is_support_DFS_mode); | |
782 | ||
783 | int mt_l2h_dvfs_mempll(void){return 0;} | |
784 | EXPORT_SYMBOL(mt_l2h_dvfs_mempll); | |
785 | ||
786 | int mt_h2l_dvfs_mempll(void){return 0;} | |
787 | EXPORT_SYMBOL(mt_h2l_dvfs_mempll); | |
788 | ||
789 | int mt_fh_dram_overclock(int clk){return 0;} | |
790 | EXPORT_SYMBOL(mt_fh_dram_overclock); | |
791 | ||
792 | int mt_fh_get_dramc(void){return 0;} | |
793 | EXPORT_SYMBOL(mt_fh_get_dramc); | |
794 | ||
795 | void mt_freqhopping_init(void){} | |
796 | EXPORT_SYMBOL(mt_freqhopping_init); | |
797 | ||
798 | void mt_freqhopping_pll_init(void){} | |
799 | EXPORT_SYMBOL(mt_freqhopping_pll_init); | |
800 | ||
801 | int mt_freqhopping_devctl(unsigned int cmd, void* args){return 0;} | |
802 | EXPORT_SYMBOL(mt_freqhopping_devctl); | |
803 | ||
804 | #else | |
805 | void mt_fh_popod_save(void) | |
806 | { | |
807 | if(!g_p_fh_hal_drv) | |
808 | { | |
809 | FH_MSG("[%s]: g_p_fh_hal_drv is uninitialized.", __func__); | |
810 | return; | |
811 | } | |
812 | FH_MSG("EN: %s",__func__); | |
813 | ||
814 | g_p_fh_hal_drv->mt_fh_popod_save(); | |
815 | } | |
816 | EXPORT_SYMBOL(mt_fh_popod_save); | |
817 | ||
818 | void mt_fh_popod_restore(void) | |
819 | { | |
820 | if(!g_p_fh_hal_drv) | |
821 | { | |
822 | FH_MSG("[%s]: g_p_fh_hal_drv is uninitialized.", __func__); | |
823 | return; | |
824 | } | |
825 | ||
826 | FH_MSG("EN: %s",__func__); | |
827 | ||
828 | g_p_fh_hal_drv->mt_fh_popod_restore(); | |
829 | } | |
830 | EXPORT_SYMBOL(mt_fh_popod_restore); | |
831 | ||
832 | int freqhopping_config(unsigned int pll_id, unsigned long vco_freq, unsigned int enable) | |
833 | { | |
834 | struct freqhopping_ioctl fh_ctl; | |
835 | unsigned int fh_status; | |
836 | unsigned long flags=0; | |
837 | unsigned int skip_flag=0; | |
838 | ||
839 | FH_MSG("conf() id: %d f: %d, e: %d",(int)pll_id, (int)vco_freq, (int)enable); | |
840 | ||
841 | if( (g_p_fh_hal_drv->mt_fh_get_init()) == 0){ | |
842 | FH_MSG("Not init yet, init first."); | |
843 | return 1; | |
844 | } | |
845 | ||
846 | g_p_fh_hal_drv->mt_fh_lock(&flags); | |
847 | ||
848 | //backup | |
849 | fh_status = g_fh_drv_pll[pll_id].fh_status; | |
850 | ||
851 | g_fh_drv_pll[pll_id].curr_freq = vco_freq; | |
852 | g_fh_drv_pll[pll_id].pll_status = (enable > 0) ? FH_PLL_ENABLE:FH_PLL_DISABLE; | |
853 | ||
854 | ||
855 | //prepare freqhopping_ioctl | |
856 | fh_ctl.pll_id = pll_id; | |
857 | ||
858 | if(g_fh_drv_pll[pll_id].fh_status != FH_FH_DISABLE){ | |
859 | //FH_MSG("+fh"); | |
860 | g_p_fh_hal_drv->mt_fh_hal_ctrl(&fh_ctl,enable); | |
861 | ||
862 | } | |
863 | else{ | |
864 | skip_flag = 1; | |
865 | //FH_MSG("-fh,skip"); | |
866 | } | |
867 | ||
868 | //restore | |
869 | g_fh_drv_pll[pll_id].fh_status = fh_status; | |
870 | ||
871 | g_p_fh_hal_drv->mt_fh_unlock(&flags); | |
872 | ||
873 | if(skip_flag) | |
874 | FH_MSG("-fh,skip"); | |
875 | ||
876 | return 0; | |
877 | } | |
878 | EXPORT_SYMBOL(freqhopping_config); | |
879 | ||
880 | ||
881 | int mt_l2h_mempll(void) | |
882 | { | |
883 | return(g_p_fh_hal_drv->mt_l2h_mempll()); | |
884 | } | |
885 | EXPORT_SYMBOL(mt_l2h_mempll); | |
886 | ||
887 | int mt_h2l_mempll(void) | |
888 | { | |
889 | return(g_p_fh_hal_drv->mt_h2l_mempll()); | |
890 | } | |
891 | EXPORT_SYMBOL(mt_h2l_mempll); | |
892 | ||
893 | int mt_dfs_armpll(unsigned int current_freq, unsigned int target_dds) | |
894 | { | |
895 | if(!g_p_fh_hal_drv) | |
896 | { | |
897 | FH_MSG("[%s]: g_p_fh_hal_drv is uninitialized.", __func__); | |
898 | return 1; | |
899 | } | |
900 | ||
901 | return(g_p_fh_hal_drv->mt_dfs_armpll(current_freq, target_dds)); | |
902 | } | |
903 | EXPORT_SYMBOL(mt_dfs_armpll); | |
904 | int mt_dfs_mmpll(unsigned int target_dds) | |
905 | { | |
906 | if(!g_p_fh_hal_drv) | |
907 | { | |
908 | FH_MSG("[%s]: g_p_fh_hal_drv is uninitialized.", __func__); | |
909 | return 1; | |
910 | } | |
911 | return(g_p_fh_hal_drv->mt_dfs_mmpll(target_dds)); | |
912 | } | |
913 | EXPORT_SYMBOL(mt_dfs_mmpll); | |
914 | int mt_dfs_vencpll(unsigned int target_dds) | |
915 | { | |
916 | if(!g_p_fh_hal_drv) | |
917 | { | |
918 | FH_MSG("[%s]: g_p_fh_hal_drv is uninitialized.", __func__); | |
919 | return 1; | |
920 | } | |
921 | ||
922 | return(g_p_fh_hal_drv->mt_dfs_vencpll(target_dds)); | |
923 | } | |
924 | EXPORT_SYMBOL(mt_dfs_vencpll); | |
925 | ||
926 | int mt_dfs_mpll(unsigned int target_dds) | |
927 | { | |
928 | if((!g_p_fh_hal_drv) || (!g_p_fh_hal_drv->mt_dfs_mpll)) | |
929 | { | |
930 | FH_MSG("[%s]: g_p_fh_hal_drv is uninitialized.", __func__); | |
931 | return 1; | |
932 | } | |
933 | ||
934 | return(g_p_fh_hal_drv->mt_dfs_mpll(target_dds)); | |
935 | ||
936 | } | |
937 | EXPORT_SYMBOL(mt_dfs_mpll); | |
938 | ||
939 | ||
940 | int mt_is_support_DFS_mode(void) | |
941 | { | |
942 | return(g_p_fh_hal_drv->mt_is_support_DFS_mode()); | |
943 | } | |
944 | EXPORT_SYMBOL(mt_is_support_DFS_mode); | |
945 | int mt_l2h_dvfs_mempll(void) | |
946 | { | |
947 | if(!g_p_fh_hal_drv) | |
948 | { | |
949 | FH_MSG("[%s]: g_p_fh_hal_drv is uninitialized.", __func__); | |
950 | return 1; | |
951 | } | |
952 | return(g_p_fh_hal_drv->mt_l2h_dvfs_mempll()); | |
953 | } | |
954 | EXPORT_SYMBOL(mt_l2h_dvfs_mempll); | |
955 | ||
956 | int mt_h2l_dvfs_mempll(void) | |
957 | { | |
958 | if(!g_p_fh_hal_drv) | |
959 | { | |
960 | FH_MSG("[%s]: g_p_fh_hal_drv is uninitialized.", __func__); | |
961 | return 1; | |
962 | } | |
963 | ||
964 | return(g_p_fh_hal_drv->mt_h2l_dvfs_mempll()); | |
965 | } | |
966 | EXPORT_SYMBOL(mt_h2l_dvfs_mempll); | |
967 | int mt_fh_dram_overclock(int clk) | |
968 | { | |
969 | return (g_p_fh_hal_drv->mt_dram_overclock(clk)); | |
970 | } | |
971 | EXPORT_SYMBOL(mt_fh_dram_overclock); | |
972 | ||
973 | int mt_fh_get_dramc(void) | |
974 | { | |
975 | return (g_p_fh_hal_drv->mt_get_dramc()); | |
976 | } | |
977 | EXPORT_SYMBOL(mt_fh_get_dramc); | |
978 | ||
979 | void mt_freqhopping_init(void) | |
980 | { | |
981 | g_p_fh_hal_drv = mt_get_fh_hal_drv(); | |
982 | ||
983 | g_p_fh_hal_drv->mt_fh_hal_init(); | |
984 | ||
985 | g_fh_drv_pll = g_p_fh_hal_drv->fh_pll; | |
986 | g_fh_drv_usr_def = g_p_fh_hal_drv->fh_usrdef; | |
987 | g_drv_pll_count = g_p_fh_hal_drv->pll_cnt; | |
988 | ||
989 | freqhopping_debug_proc_init(); | |
990 | platform_driver_register(&freqhopping_driver); | |
991 | ||
992 | mt_freqhopping_pll_init(); //TODO_HAL: wait for clkmgr to invoke this function | |
993 | } | |
994 | EXPORT_SYMBOL(mt_freqhopping_init); | |
995 | ||
996 | void mt_freqhopping_pll_init(void) | |
997 | { | |
998 | g_p_fh_hal_drv->mt_fh_default_conf(); | |
999 | } | |
1000 | EXPORT_SYMBOL(mt_freqhopping_pll_init); | |
1001 | ||
1002 | int mt_freqhopping_devctl(unsigned int cmd, void* args) | |
1003 | { | |
1004 | if(!g_p_fh_hal_drv) | |
1005 | { | |
1006 | return 1; | |
1007 | } | |
1008 | ||
4b9e9796 | 1009 | //g_p_fh_hal_drv->ioctl(cmd, args); |
6fa3eb70 S |
1010 | return 0; |
1011 | ||
1012 | } | |
1013 | EXPORT_SYMBOL(mt_freqhopping_devctl); | |
1014 | ||
1015 | ||
1016 | #endif |