blob: 122ce0a30c8c497f26318532f1ef13a193fd8c00 [file] [log] [blame]
xjb04a4022021-11-25 15:01:52 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2019 MediaTek Inc.
4 * Author: Pierre Lee <pierre.lee@mediatek.com>
5 */
6
7#include <linux/clk.h>
8#include <linux/clk-provider.h>
9#include <linux/debugfs.h>
10#include <linux/delay.h>
11#include <linux/init.h>
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/of.h>
15#include <linux/of_address.h>
16#include <linux/proc_fs.h>
17#include <linux/platform_device.h>
18#include <linux/seq_file.h>
19#include <linux/uaccess.h>
20#include "clk-fhctl.h"
21#include "clk-mtk.h"
22#include <mt-plat/aee.h>
23
24
25
26
27
28struct pll_status fh_log;
29static struct mtk_fhctl *g_p_fhctl;
30
31
32/*****************************************************************
33 * Global variable operation
34 ****************************************************************/
35static void __set_fhctl(struct mtk_fhctl *pfhctl)
36{
37 g_p_fhctl = pfhctl;
38}
39
40static struct mtk_fhctl *__get_fhctl(void)
41{
42 return g_p_fhctl;
43}
44
45
46enum FH_DEBUG_CMD_ID {
47 FH_DBG_CMD_ID = 0x1000,
48 FH_DBG_CMD_DVFS = 0x1001,
49 FH_DBG_CMD_DVFS_API = 0x1002,
50 FH_DBG_CMD_DVFS_SSC_ENABLE = 0x1003,
51 FH_DBG_CMD_SSC_ENABLE = 0x1004,
52 FH_DBG_CMD_SSC_DISABLE = 0x1005,
53 FH_DBG_CMD_TR_BEGIN_LOW = 0x2001,
54 FH_DBG_CMD_TR_BEGIN_HIGH = 0x2002,
55 FH_DBG_CMD_TR_END_LOW = 0x2003,
56 FH_DBG_CMD_TR_END_HIGH = 0x2004,
57 FH_DBG_CMD_TR_ID = 0x2005,
58 FH_DBG_CMD_TR_VAL = 0x2006,
59 FH_DBG_CMD_MAX
60};
61
62void mt_fhctl_exit_debugfs(struct mtk_fhctl *fhctl)
63{
64 debugfs_remove_recursive(fhctl->debugfs_root);
65}
66
67void mt_fh_dump_register(void)
68{
69 int pll_id;
70 struct mtk_fhctl *fhctl = __get_fhctl();
71 struct clk_mt_fhctl_regs *fh_regs;
72
73 if (fhctl == NULL){
74 WARN_ON(1);
75 pr_info("[Hopping] get NULL fhctl obj \n");
76 }
77
78
79 for (pll_id = 0 ; pll_id < fhctl->pll_num ; pll_id++) {
80
81 if (fhctl->fh_tbl[pll_id] == NULL || (fhctl->idmap[pll_id] == -1)){
82 continue;
83 }
84 fh_regs = fhctl->fh_tbl[pll_id]->fh_regs ;
85
86 pr_info("PLL_ID:%d HP_EN:%08x\n",pll_id, readl(fh_regs->reg_hp_en));
87 pr_info("P:%s CFG:%08x DVFS:%08x DDS:%08x MON:%08x CON_PCW:%08x\n",
88 fhctl->fh_tbl[pll_id]->pll_data->pll_name,
89 readl(fh_regs->reg_cfg),
90 readl(fh_regs->reg_dvfs),
91 readl(fh_regs->reg_dds),
92 readl(fh_regs->reg_mon),
93 readl(fh_regs->reg_con_pcw));
94
95 }
96}
97
98
99void mt_fhctl_log_b4_hopping (struct clk_mt_fhctl *fhctl, unsigned int target_dds, unsigned int tx_id, struct pll_status *fh_log){
100
101 unsigned int pll_id = fhctl->pll_data->pll_id;
102
103 //recording
104 fh_log->before_dds = readl(fhctl->fh_regs->reg_con_pcw) & (0x3FFFF);
105
106 fh_log->target_dds = target_dds;
107
108 fh_log->pll_id = pll_id;
109
110 fh_log->tx_id = tx_id;
111}
112
113
114void mt_fhctl_log_af_hopping (struct clk_mt_fhctl *fhctl, int ret_from_ipi, unsigned int ack_data, struct pll_status *fh_log, void (*ipi_get_data)(unsigned int), u64 time_ns){
115
116 unsigned int pll_id = fhctl->pll_data->pll_id;
117 unsigned int aft_dds = readl(fhctl->fh_regs->reg_con_pcw) & (0x3FFFFF);
118 struct mtk_fhctl *fh = __get_fhctl();
119
120 if ((aft_dds != fh_log->target_dds) || (fh_log->tx_id != ack_data) || (ret_from_ipi != 0)) {
121 pr_info("[Hopping] PLL_ID:%d TX_ID:%d ACK_DATA:%d", pll_id, fh_log->tx_id, ack_data);
122 pr_info("[Hopping] pll_id %d hopping fail, cfg %x, bef %x, aft %x, tgt %x, ret_from_ipi %d, time_ns %llx\n",
123 pll_id,
124 readl(fhctl->fh_regs->reg_cfg),
125 fh_log->before_dds,
126 aft_dds,
127 fh_log->target_dds,
128 ret_from_ipi,
129 time_ns);
130
131 fh_log->after_dds = aft_dds;
132
133 mt_fh_dump_register();
134
135 if (fh->reg_tr)
136 pr_info("[Hopping] reg_tr<%x>\n", readl(fh->reg_tr));
137
138 ipi_get_data(FH_DBG_CMD_TR_BEGIN_LOW);
139 ipi_get_data(FH_DBG_CMD_TR_BEGIN_HIGH);
140 ipi_get_data(FH_DBG_CMD_TR_END_LOW);
141 ipi_get_data(FH_DBG_CMD_TR_END_HIGH);
142 ipi_get_data(FH_DBG_CMD_TR_ID);
143 ipi_get_data(FH_DBG_CMD_TR_VAL);
144
145 aee_kernel_warning_api(__FILE__, __LINE__,
146 DB_OPT_DUMMY_DUMP | DB_OPT_FTRACE,
147 "[Hopping] IPI to CPUEB\n",
148 "IPI timeout");
149
150 //BUG();
151 }
152
153}
154
155
156static int __fh_ctrl_cmd_handler(struct clk_mt_fhctl *fh,
157 unsigned int cmd,
158 int pll_id,
159 unsigned int p1)
160
161{
162 int ret;
163
164 pr_info("pll_id:0x%x cmd: %x p1:%x", pll_id, cmd, p1);
165
166 if (fh == NULL) {
167 pr_info("Error: fh is null!");
168 return 0;
169 }
170
171 switch (cmd) {
172 case FH_DBG_CMD_SSC_ENABLE:
173 ret = fh->hal_ops->pll_ssc_enable(fh, p1);
174 break;
175 case FH_DBG_CMD_SSC_DISABLE:
176 ret = fh->hal_ops->pll_ssc_disable(fh);
177 break;
178 case FH_DBG_CMD_DVFS:
179 ret = fh->hal_ops->pll_hopping(fh, p1, -1);
180 break;
181 case FH_DBG_CMD_DVFS_API:
182 ret = !(mtk_fh_set_rate(pll_id, p1, -1));
183 break;
184 default:
185 pr_info(" Not Support CMD:%x\n", cmd);
186 ret = -EINVAL;
187 break;
188 }
189
190 if (ret)
191 pr_info(" Debug CMD fail err:%d\n", ret);
192
193 return ret;
194}
195
196
197/***************************************************************************
198 * FHCTL Debug CTRL OPS
199 ***************************************************************************/
200static ssize_t fh_ctrl_proc_write(struct file *file,
201 const char *buffer, size_t count, loff_t *data)
202{
203 int ret, n;
204 char kbuf[256];
205 int pll_id;
206 size_t len = 0;
207 unsigned int cmd, p1;
208 struct clk_mt_fhctl *fh;
209 struct mtk_fhctl *fhctl = file->f_inode->i_private;
210
211 len = min(count, (sizeof(kbuf) - 1));
212
213 pr_info("count: %ld", count);
214 if (count == 0)
215 return -1;
216
217 if (count > 255)
218 count = 255;
219
220 ret = copy_from_user(kbuf, buffer, count);
221 if (ret < 0)
222 return -1;
223
224 kbuf[count] = '\0';
225
226 n = sscanf(kbuf, "%x %x %x", &cmd, &pll_id, &p1);
227 if ((n != 3) && (n != 2)) {
228 pr_info("error input format\n");
229 return -EINVAL;
230 }
231
232 pr_info("pll:0x%x cmd:%x p1:%x", pll_id, cmd, p1);
233
234 if ((cmd < FH_DBG_CMD_ID) && (cmd > FH_DBG_CMD_MAX)) {
235 pr_info("cmd not support:%x", cmd);
236 return -EINVAL;
237 }
238
239 if (pll_id >= fhctl->pll_num) {
240 pr_info("pll_id is illegal:%d", pll_id);
241 return -EINVAL;
242 }
243
244 fh = mtk_fh_get_fh_obj_tbl(fhctl, pll_id);
245
246 __fh_ctrl_cmd_handler(fh, cmd, pll_id, p1);
247
248 pr_debug("reg_cfg:0x%08x", readl(fh->fh_regs->reg_cfg));
249 pr_debug("reg_updnlmt:0x%08x", readl(fh->fh_regs->reg_updnlmt));
250 pr_debug("reg_dds:0x%08x", readl(fh->fh_regs->reg_dds));
251 pr_debug("reg_dvfs:0x%08x", readl(fh->fh_regs->reg_dvfs));
252 pr_debug("reg_mon:0x%08x", readl(fh->fh_regs->reg_mon));
253 pr_debug("reg_con0:0x%08x", readl(fh->fh_regs->reg_con0));
254 pr_debug("reg_con_pcw:0x%08x", readl(fh->fh_regs->reg_con_pcw));
255
256 return count;
257}
258
259static int fh_ctrl_proc_read(struct seq_file *m, void *v)
260{
261 int i;
262 struct mtk_fhctl *fhctl = m->private;
263
264 seq_puts(m, "====== FHCTL CTRL Description ======\n");
265
266 seq_puts(m, "[PLL Name and ID Table]\n");
267 for (i = 0 ; i < fhctl->pll_num ; i++)
268 seq_printf(m, "PLL_ID:%d PLL_NAME: %s\n",
269 i, fhctl->fh_tbl[i]->pll_data->pll_name);
270
271 seq_puts(m, "\n[Command Description]\n");
272 seq_puts(m, " [SSC Enable]\n");
273 seq_puts(m, " /> echo '1004 <PLL-ID> <SSC-Rate>' > ctrl\n");
274 seq_puts(m, " Example: echo '1004 2 2' > ctrl\n");
275 seq_puts(m, " [SSC Disable]\n");
276 seq_puts(m, " /> echo '1005 <PLL-ID>' > ctrl\n");
277 seq_puts(m, " Example: echo '1005 2' > ctrl\n");
278 seq_puts(m, " [SSC Hopping]\n");
279 seq_puts(m, " /> echo '1001 <PLL-ID> <DDS>' > ctrl\n");
280 seq_puts(m, " Example: echo '1001 2 ec200' > ctrl\n");
281 seq_puts(m, " [CLK API Hopping]\n");
282 seq_puts(m, " /> echo '1002 <PLL-ID> <DDS>' > ctrl\n");
283 seq_puts(m, " Example: echo '1002 2 ec200' > ctrl\n");
284
285 return 0;
286}
287
288
289static int fh_ctrl_proc_open(struct inode *inode, struct file *file)
290{
291 return single_open(file, fh_ctrl_proc_read, inode->i_private);
292}
293
294static const struct file_operations ctrl_fops = {
295 .owner = THIS_MODULE,
296 .open = fh_ctrl_proc_open,
297 .read = seq_read,
298 .write = fh_ctrl_proc_write,
299 .release = single_release,
300};
301
302static int __sample_period_dds(struct clk_mt_fhctl *fh)
303{
304 int i, ssc_rate = 0;
305 struct clk_mt_fhctl_regs *fh_regs;
306 unsigned int mon_dds;
307 unsigned int dds;
308
309 fh_regs = fh->fh_regs;
310
311 mon_dds = readl(fh_regs->reg_mon) & fh->pll_data->dds_mask;
312 dds = readl(fh_regs->reg_dds) & fh->pll_data->dds_mask;
313
314 fh->pll_data->dds_max = dds;
315 fh->pll_data->dds_min = mon_dds;
316
317
318 /* Sample 200*10us */
319 for (i = 0 ; i < 200 ; i++) {
320 mon_dds = readl(fh_regs->reg_mon) & fh->pll_data->dds_mask;
321
322 if (mon_dds > fh->pll_data->dds_max)
323 fh->pll_data->dds_max = mon_dds;
324
325 if (mon_dds < fh->pll_data->dds_min)
326 fh->pll_data->dds_min = mon_dds;
327
328 udelay(10);
329 }
330
331 if ((fh->pll_data->dds_max == 0) ||
332 (fh->pll_data->dds_min == 0))
333 ssc_rate = 0;
334 else {
335 int diff = (fh->pll_data->dds_max - fh->pll_data->dds_min);
336
337 ssc_rate = (diff * 1000) / fh->pll_data->dds_max;
338 }
339
340 return ssc_rate;
341}
342
343static int mt_fh_dumpregs_read(struct seq_file *m, void *data)
344{
345 struct mtk_fhctl *fhctl = dev_get_drvdata(m->private);
346 int i, ssc_rate;
347 struct clk_mt_fhctl *fh;
348 struct clk_mt_fhctl_regs *fh_regs;
349
350 if (fhctl == NULL) {
351 seq_puts(m, "Cannot Get FHCTL driver data\n");
352 return 0;
353 }
354
355 seq_puts(m, "FHCTL dumpregs Read\n");
356
357 for (i = 0; i < fhctl->pll_num ; i++) {
358 fh = mtk_fh_get_fh_obj_tbl(fhctl, i);
359 if (fh == NULL) {
360 pr_info(" fh:NULL pll_id:%d", i);
361 seq_printf(m, "ERROR PLL_ID:%d clk_mt_fhctl is NULL\r\n", i);
362 return 0;
363 }
364
365 if (fh->pll_data->pll_type == FH_PLL_TYPE_NOT_SUPPORT) {
366 pr_debug(" Not support: %s", fh->pll_data->pll_name);
367 continue;
368 }
369
370 fh_regs = fh->fh_regs;
371 if (fh_regs == NULL) {
372 pr_info("%s Not support dumpregs!",
373 fh->pll_data->pll_name);
374 seq_printf(m, "PLL_%d: %s Not support dumpregs!\n",
375 i, fh->pll_data->pll_name);
376 continue;
377 }
378
379 pr_debug("fh:0x%p fh_regs:0x%p", fh, fh_regs);
380
381 if (i == 0) {
382 seq_printf(m, "\r\nFHCTL_HP_EN:\r\n0x%08x\r\n",
383 readl(fh_regs->reg_hp_en));
384 seq_printf(m, "\r\nFHCTL_CLK_CON:\r\n0x%08x\r\n",
385 readl(fh_regs->reg_clk_con));
386 seq_printf(m, "\r\nFHCTL_SLOPE0:\r\n0x%08x\r\n",
387 readl(fh_regs->reg_slope0));
388 seq_printf(m, "\r\nFHCTL_SLOPE1:\r\n0x%08x\r\n\n",
389 readl(fh_regs->reg_slope1));
390 }
391
392 ssc_rate = __sample_period_dds(fh);
393
394 seq_printf(m, "PLL_ID:%d (%s) type:%d \r\n",
395 i, fh->pll_data->pll_name, fh->pll_data->pll_type);
396
397 seq_puts(m, "CFG, UPDNLMT, DDS, DVFS, MON\r\n");
398 seq_printf(m, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\r\n",
399 readl(fh_regs->reg_cfg), readl(fh_regs->reg_updnlmt),
400 readl(fh_regs->reg_dds), readl(fh_regs->reg_dvfs),
401 readl(fh_regs->reg_mon));
402 seq_puts(m, "CON0, CON_PCW\r\n");
403 seq_printf(m, "0x%08x 0x%08x\r\n",
404 readl(fh_regs->reg_con0), readl(fh_regs->reg_con_pcw));
405
406 seq_printf(m,
407 "DDS max:0x%08x min:0x%08x ssc(1/1000):%d\r\n\r\n",
408 fh->pll_data->dds_max,
409 fh->pll_data->dds_min,
410 ssc_rate);
411
412
413 pr_debug("pll_id:%d", i);
414 pr_debug("pll_type:%d", fh->pll_data->pll_type);
415 pr_debug("reg_hp_en:0x%08x", readl(fh_regs->reg_hp_en));
416 pr_debug("reg_clk_con:0x%08x", readl(fh_regs->reg_clk_con));
417 pr_debug("reg_rst_con:0x%08x", readl(fh_regs->reg_rst_con));
418 pr_debug("reg_slope0:0x%08x", readl(fh_regs->reg_slope0));
419 pr_debug("reg_slope1:0x%08x", readl(fh_regs->reg_slope1));
420
421 pr_debug("reg_cfg:0x%08x", readl(fh_regs->reg_cfg));
422 pr_debug("reg_updnlmt:0x%08x", readl(fh_regs->reg_updnlmt));
423 pr_debug("reg_dds:0x%08x", readl(fh_regs->reg_dds));
424 pr_debug("reg_dvfs:0x%08x", readl(fh_regs->reg_dvfs));
425 pr_debug("reg_mon:0x%08x", readl(fh_regs->reg_mon));
426 pr_debug("reg_con0:0x%08x", readl(fh_regs->reg_con0));
427 pr_debug("reg_con_pcw:0x%08x", readl(fh_regs->reg_con_pcw));
428
429 }
430 return 0;
431}
432
433void mt_fhctl_init_debugfs(struct mtk_fhctl *fhctl)
434{
435 struct dentry *root;
436 struct dentry *fh_dumpregs_dir;
437 struct dentry *fh_ctrl_dir;
438 struct device *dev = fhctl->dev;
439
440 root = debugfs_create_dir("fhctl", NULL);
441 if (IS_ERR(root)) {
442 dev_info(dev, "create debugfs fail");
443 return;
444 }
445 __set_fhctl(fhctl);
446 fhctl->debugfs_root = root;
447
448 /* /sys/kernel/debug/fhctl/dumpregs */
449 fh_dumpregs_dir = debugfs_create_devm_seqfile(dev,
450 "dumpregs", root, mt_fh_dumpregs_read);
451 if (IS_ERR(fh_dumpregs_dir)) {
452 dev_info(dev, "failed to create dumpregs debugfs");
453 return;
454 }
455
456 /* /sys/kernel/debug/fhctl/ctrl */
457 fh_ctrl_dir = debugfs_create_file("ctrl", 0664,
458 root, fhctl, &ctrl_fops);
459 if (IS_ERR(fh_ctrl_dir)) {
460 dev_info(dev, "failed to create ctrl debugfs");
461 return;
462 }
463
464 dev_dbg(dev, "Create debugfs success!");
465}
466
467