A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2014 by Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "std_analysers.h"
22#include <QDebug>
23
24/**
25 * AnalyserEx
26 */
27
28AnalyserEx::AnalyserEx(const soc_desc::soc_ref_t& soc, IoBackend *backend)
29 :Analyser(soc, backend), m_helper(backend, soc)
30{
31}
32
33bool AnalyserEx::ReadRegister(const QString& path, soc_word_t& val)
34{
35 return m_helper.ReadRegister(m_helper.ParsePath(path), val);
36}
37
38bool AnalyserEx::ReadRegisterOld(const QString& dev, const QString& reg, soc_word_t& val)
39{
40 return ReadRegister(dev + "." + reg, val);
41}
42
43bool AnalyserEx::ReadField(const QString& path, const QString& field, soc_word_t& val)
44{
45 return m_helper.ReadRegisterField(m_helper.ParsePath(path), field, val);
46}
47
48bool AnalyserEx::ReadFieldOld(const QString& dev, const QString& reg,
49 const QString& field, soc_word_t& val)
50{
51 return ReadField(dev + "." + reg, field, val);
52}
53
54/**
55 * Clock analyser
56 */
57
58ClockAnalyser::ClockAnalyser(const soc_desc::soc_ref_t& soc, IoBackend *backend)
59 :AnalyserEx(soc, backend)
60{
61 m_group = new QGroupBox("Clock Analyser");
62 QVBoxLayout *layout = new QVBoxLayout;
63 m_group->setLayout(layout);
64 m_tree_widget = new QTreeWidget;
65 layout->addWidget(m_tree_widget);
66
67 m_tree_widget->setColumnCount(2);
68 QStringList list;
69 list << "Name" << "Frequency";
70 m_tree_widget->setHeaderLabels(list);
71
72 FillTree();
73}
74
75ClockAnalyser::~ClockAnalyser()
76{
77 delete m_group;
78}
79
80QWidget *ClockAnalyser::GetWidget()
81{
82 return m_group;
83}
84
85bool ClockAnalyser::SupportSoc(const QString& soc_name)
86{
87 return soc_name == "imx233"
88 || soc_name == "rk27xx"
89 || soc_name == "atj213x"
90 || soc_name == "jz4760b"
91 || soc_name == "stmp3700";
92}
93
94QString ClockAnalyser::GetFreq(unsigned freq)
95{
96 if(freq >= 1000000)
97 {
98 if((freq % 1000000) == 0)
99 return QString().sprintf("%d MHz", freq / 1000000);
100 else
101 return QString().sprintf("%.3f MHz", freq / 1000000.0);
102 }
103 if(freq >= 1000)
104 {
105 if((freq % 1000) == 0)
106 return QString().sprintf("%d KHz", freq / 1000);
107 else
108 return QString().sprintf("%.3f KHz", freq / 1000.0);
109 }
110 return QString().sprintf("%d Hz", freq);
111}
112
113QTreeWidgetItem *ClockAnalyser::AddClock(QTreeWidgetItem *parent, const QString& name,
114 int freq, int mul, int div)
115{
116 if(freq == FROM_PARENT)
117 {
118 int64_t f = GetClockFreq(parent);
119 f *= mul;
120 f /= div;
121 freq = f;
122 }
123 QTreeWidgetItem *item = new QTreeWidgetItem(parent, QStringList() << name
124 << (freq == INVALID ? "<invalid>" : freq == 0 ? "<disabled>" : GetFreq(freq)));
125 item->setData(1, Qt::UserRole, freq);
126 if(freq == DISABLED || freq == INVALID || (parent && parent->isDisabled()))
127 item->setDisabled(true);
128 if(!parent)
129 m_tree_widget->addTopLevelItem(item);
130 return item;
131}
132
133int ClockAnalyser::GetClockFreq(QTreeWidgetItem *item)
134{
135 return item->data(1, Qt::UserRole).toInt();
136}
137
138void ClockAnalyser::FillTree()
139{
140 m_tree_widget->clear();
141 if(m_soc.get()->name == "imx233") FillTreeIMX233();
142 if(m_soc.get()->name == "stmp3700") FillTreeIMX233();
143 else if(m_soc.get()->name == "rk27xx") FillTreeRK27XX();
144 else if(m_soc.get()->name == "atj213x") FillTreeATJ213X();
145 else if(m_soc.get()->name == "jz4760b") FillTreeJZ4760B();
146 m_tree_widget->expandAll();
147 m_tree_widget->resizeColumnToContents(0);
148}
149
150void ClockAnalyser::FillTreeJZ4760B()
151{
152 AddClock(0, "RTCLK", 32768);
153 // assume EXCLK is 12MHz, we have no way to knowing for sure but this is the
154 // recommended value anyway
155 QTreeWidgetItem *exclk = AddClock(0, "EXCLK", 12000000);
156 // PLL0
157 soc_word_t pllm, plln, pllod, pllbypass;
158 QTreeWidgetItem *pll0 = 0;
159 if(ReadFieldOld("CPM", "PLLCTRL0", "FEED_DIV", pllm) &&
160 ReadFieldOld("CPM", "PLLCTRL0", "IN_DIV", plln) &&
161 ReadFieldOld("CPM", "PLLCTRL0", "OUT_DIV", pllod) &&
162 ReadFieldOld("CPM", "PLLCTRL0", "BYPASS", pllbypass))
163 {
164 pll0 = AddClock(exclk, "PLL0", FROM_PARENT, pllbypass ? 1 : 2 * pllm,
165 pllbypass ? 1 : plln * (1 << pllod));
166 }
167 else
168 pll0 = AddClock(exclk, "PLL0", INVALID);
169 // PLL1
170 soc_word_t plldiv, src_sel;
171 QTreeWidgetItem *pll1 = 0;
172 if(ReadFieldOld("CPM", "PLLCTRL1", "FEED_DIV", pllm) &&
173 ReadFieldOld("CPM", "PLLCTRL1", "IN_DIV", plln) &&
174 ReadFieldOld("CPM", "PLLCTRL1", "OUT_DIV", pllod) &&
175 ReadFieldOld("CPM", "PLLCTRL1", "SRC_SEL", src_sel) &&
176 ReadFieldOld("CPM", "PLLCTRL1", "PLL0_DIV", plldiv))
177 {
178 pll1 = AddClock(src_sel ? pll0 : exclk, "PLL1", FROM_PARENT, 2 * pllm,
179 plln * (1 << pllod) * (src_sel ? plldiv : 1));
180 }
181 else
182 pll1 = AddClock(exclk, "PLL1", INVALID);
183 // system clocks
184 const int NR_SYSCLK = 6;
185 const char *sysclk[NR_SYSCLK] = { "CCLK", "SCLK", "PCLK", "HCLK", "H2CLK", "MCLK"};
186 for(int i = 0; i < NR_SYSCLK; i++)
187 {
188 soc_word_t div = 0;
189 std::string field = std::string(sysclk[i]) + "_DIV";
190 if(ReadFieldOld("CPM", "SYSCLK", field.c_str(), div))
191 {
192 switch(div)
193 {
194 case 0: div = 1; break;
195 case 1: div = 2; break;
196 case 2: div = 3; break;
197 case 3: div = 4; break;
198 case 4: div = 6; break;
199 case 5: div = 8; break;
200 default: div = 0; break;
201 }
202 }
203 if(div != 0)
204 AddClock(pll0, sysclk[i], FROM_PARENT, 1, div);
205 else
206 AddClock(pll0, sysclk[i], INVALID);
207 }
208 // common to msc, i2s, lcd, uhc, otg, ssi, pcm, gpu, gps
209 soc_word_t pll_div;
210 if(ReadFieldOld("CPM", "SYSCLK", "PLL_DIV", pll_div))
211 pll_div = pll_div ? 1 : 2;
212 else
213 pll_div = 1; // error
214 // lcd
215 soc_word_t pll_sel, div;
216 if(ReadFieldOld("CPM", "LCDCLK", "DIV", div) &&
217 ReadFieldOld("CPM", "LCDCLK", "PLL_SEL", pll_sel))
218 {
219 AddClock(pll_sel ? pll1 : pll0, "LCDCLK",
220 FROM_PARENT, 1, pll_div * (div + 1));
221 }
222 else
223 AddClock(exclk, "LCDCLK", INVALID);
224}
225
226void ClockAnalyser::FillTreeATJ213X()
227{
228 soc_word_t pllbypass, pllclk, en, coreclks, tmp0, tmp1, tmp2, tmp3;
229
230 // system oscillators 32.768k and 24M
231 QTreeWidgetItem *losc_clk = AddClock(0, "losc clk", 32768);
232 QTreeWidgetItem *hosc_clk = AddClock(0, "hosc clk", 24000000);
233
234 // core pll
235 QTreeWidgetItem *corepll = 0;
236 if(ReadFieldOld("CMU", "COREPLL", "CPEN", en) &&
237 ReadFieldOld("CMU", "COREPLL", "CPBY", pllbypass) &&
238 ReadFieldOld("CMU", "COREPLL", "CPCK", pllclk))
239 {
240 corepll = AddClock(hosc_clk, "core pll", en ? FROM_PARENT : DISABLED,
241 pllbypass ? 1 : pllclk, pllbypass ? 1 : 4);
242 }
243 else
244 {
245 corepll = AddClock(hosc_clk, "core pll", INVALID);
246 }
247
248 // dsp pll
249 QTreeWidgetItem *dsppll = 0;
250 if(ReadFieldOld("CMU", "DSPPLL", "DPEN", en) &&
251 ReadFieldOld("CMU", "DSPPLL", "DPCK", pllclk))
252 {
253 dsppll = AddClock(hosc_clk, "dsp pll", en ? FROM_PARENT : DISABLED,
254 pllbypass ? 1 : pllclk, pllbypass ? 1 : 4);
255 }
256 else
257 {
258 dsppll = AddClock(hosc_clk, "dsp pll", INVALID);
259 }
260
261 // audio pll
262 QTreeWidgetItem *adcpll = 0;
263 QTreeWidgetItem *dacpll = 0;
264 if(ReadFieldOld("CMU", "AUDIOPLL", "APEN", en) &&
265 ReadFieldOld("CMU", "AUDIOPLL", "ADCCLK", tmp0) &&
266 ReadFieldOld("CMU", "AUDIOPLL", "DACCLK", tmp1))
267 {
268 if(en)
269 {
270 adcpll = AddClock(hosc_clk, "audio adc pll", tmp0 ? 22579200 : 24576000);
271 dacpll = AddClock(hosc_clk, "audio dac pll", tmp1 ? 22579200 : 24576000);
272 }
273 else
274 {
275 adcpll = AddClock(hosc_clk, "audio adc pll", DISABLED);
276 dacpll = AddClock(hosc_clk, "audio dac pll", DISABLED);
277 }
278 }
279 else
280 {
281 adcpll = AddClock(hosc_clk, "audio adc pll", INVALID);
282 dacpll = AddClock(hosc_clk, "audio dac pll", INVALID);
283 }
284
285 // audio clocks
286 QTreeWidgetItem *adcclk = 0;
287 QTreeWidgetItem *dacclk = 0;
288 if(ReadFieldOld("CMU", "AUDIOPLL", "ADCCLK", tmp0) &&
289 ReadFieldOld("CMU", "AUDIOPLL", "DACCLK", tmp1))
290 {
291 adcclk = AddClock(adcpll, "audio adc clk", FROM_PARENT, 1, tmp0+1);
292 dacclk = AddClock(dacpll, "audio dac clk", FROM_PARENT, 1, tmp1+1);
293 }
294 else
295 {
296 adcclk = AddClock(adcpll, "audio adc clk", INVALID);
297 dacclk = AddClock(adcpll, "audio dac clk", INVALID);
298 }
299
300 // cpu clock
301 QTreeWidgetItem *cpuclk = 0;
302 if(ReadFieldOld("CMU", "BUSCLK", "CORECLKS", coreclks) &&
303 ReadFieldOld("CMU", "BUSCLK", "CCLKDIV", tmp0))
304 {
305 if(coreclks == 0)
306 cpuclk = AddClock(losc_clk, "cpu clk", FROM_PARENT, 1, tmp0+1);
307 else if(coreclks == 1)
308 cpuclk = AddClock(hosc_clk, "cpu clk", FROM_PARENT, 1, tmp0+1);
309 else if(coreclks == 2)
310 cpuclk = AddClock(corepll, "cpu clk", FROM_PARENT, 1, tmp0+1);
311 else
312 cpuclk = AddClock(corepll, "cpu clk", INVALID);
313 }
314 else
315 {
316 cpuclk = AddClock(corepll, "cpu clk", INVALID);
317 }
318
319 // system clock
320 QTreeWidgetItem *sysclk = 0;
321 if(ReadFieldOld("CMU", "BUSCLK", "SCLKDIV", tmp0))
322 sysclk = AddClock(cpuclk, "system clk", FROM_PARENT, 1, tmp0+1);
323 else
324 sysclk = AddClock(cpuclk, "system clk", INVALID);
325
326 // peripherial clk
327 QTreeWidgetItem *pclk = 0;
328 if(ReadFieldOld("CMU", "BUSCLK", "PCLKDIV", tmp0))
329 pclk = AddClock(sysclk, "peripherial clk", FROM_PARENT, 1, tmp0 ? tmp0+1 : 2);
330 else
331 pclk = AddClock(sysclk, "peripherial clk", INVALID);
332
333 // sdram clk
334 QTreeWidgetItem *sdrclk = 0;
335 if(ReadFieldOld("CMU", "DEVCLKEN", "SDRC", en) &&
336 ReadFieldOld("CMU", "DEVCLKEN", "SDRM", tmp0) &&
337 ReadFieldOld("SDR", "EN", "EN", tmp1) &&
338 ReadFieldOld("CMU", "SDRCLK", "SDRDIV", tmp2))
339 {
340 en &= tmp0 & tmp1;
341 sdrclk = AddClock(sysclk, "sdram clk", en ? FROM_PARENT: DISABLED, 1, tmp2+1);
342 }
343 else
344 sdrclk = AddClock(sysclk, "sdram clk", INVALID);
345
346 // nand clk
347 QTreeWidgetItem *nandclk = 0;
348 if(ReadFieldOld("CMU", "DEVCLKEN", "NAND", en) &&
349 ReadFieldOld("CMU", "NANDCLK", "NANDDIV", tmp0))
350 nandclk = AddClock(corepll, "nand clk", en ? FROM_PARENT : DISABLED, 1, tmp0+1);
351 else
352 nandclk = AddClock(corepll, "nand clk", INVALID);
353
354 // sd clk
355 QTreeWidgetItem *sdclk = 0;
356 if(ReadFieldOld("CMU", "DEVCLKEN", "SD", tmp0) &&
357 ReadFieldOld("CMU", "SDCLK", "CKEN" , tmp1) &&
358 ReadFieldOld("CMU", "SDCLK", "D128" , tmp2) &&
359 ReadFieldOld("CMU", "SDCLK", "SDDIV" , tmp3))
360 {
361 en = tmp0 & tmp1;
362 sdclk = AddClock(corepll, "sd clk", en ? FROM_PARENT : DISABLED,
363 1, tmp2 ? 128*(tmp3+1) : (tmp3));
364 }
365 else
366 sdclk = AddClock(corepll, "sd clk", INVALID);
367
368 // mha clk
369 QTreeWidgetItem *mhaclk = 0;
370 if(ReadFieldOld("CMU", "DEVCLKEN", "MHA", en) &&
371 ReadFieldOld("CMU", "MHACLK", "MHADIV", tmp1))
372 mhaclk = AddClock(corepll, "mha clk", en ? FROM_PARENT : DISABLED,
373 1, tmp1+1);
374 else
375 mhaclk = AddClock(corepll, "mha clk", INVALID);
376
377 // mca clk
378 QTreeWidgetItem *mcaclk = 0;
379 if(ReadFieldOld("CMU", "DEVCLKEN", "MCA", en) &&
380 ReadFieldOld("CMU", "MCACLK", "MCADIV", tmp1))
381 mcaclk = AddClock(corepll, "mca clk", en ? FROM_PARENT : DISABLED,
382 1, tmp1+1);
383 else
384 mcaclk = AddClock(corepll, "mca clk", INVALID);
385
386 // backlight pwm
387 QTreeWidgetItem *pwmclk = 0;
388 if(ReadFieldOld("CMU", "FMCLK", "BCKE", en) &&
389 ReadFieldOld("CMU", "FMCLK", "BCKS", tmp1) &&
390 ReadFieldOld("CMU", "FMCLK", "BCKCON", tmp2))
391 {
392 if(tmp1)
393 {
394 // HOSC/8 input clk
395 pwmclk = AddClock(hosc_clk, "pwm clk", en ? FROM_PARENT : DISABLED,
396 1, 3*(tmp2+1));
397 }
398 else
399 {
400 // LOSC input clk
401 pwmclk = AddClock(losc_clk, "pwm clk", en ? FROM_PARENT : DISABLED,
402 1, tmp2+1);
403 }
404 }
405 else
406 pwmclk = AddClock(losc_clk, "pwm clk", INVALID);
407
408 // i2c clk
409 QTreeWidgetItem *i2c1clk = 0;
410 QTreeWidgetItem *i2c2clk = 0;
411 if(ReadFieldOld("CMU", "DEVCLKEN", "I2C", en) &&
412 ReadFieldOld("I2C1", "CTL", "EN", tmp0) &&
413 ReadFieldOld("I2C1", "CLKDIV", "CLKDIV", tmp1))
414 {
415 en &= tmp0;
416 i2c1clk = AddClock(pclk, "i2c1 clk", en ? FROM_PARENT : DISABLED,
417 1, 16*(tmp1+1));
418 }
419 else
420 {
421 i2c1clk = AddClock(pclk, "i2c1 clk", INVALID);
422 }
423
424 if(ReadFieldOld("CMU", "DEVCLKEN", "I2C", en) &&
425 ReadFieldOld("I2C2", "CTL", "EN", tmp0) &&
426 ReadFieldOld("I2C2", "CLKDIV", "CLKDIV", tmp1))
427 {
428 en &= tmp0;
429 i2c2clk = AddClock(pclk, "i2c2 clk", en ? FROM_PARENT : DISABLED,
430 1, 16*(tmp1+1));
431 }
432 else
433 {
434 i2c2clk = AddClock(pclk, "i2c2 clk", INVALID);
435 }
436
437 Q_UNUSED(dsppll);
438 Q_UNUSED(adcclk);
439 Q_UNUSED(dacclk);
440 Q_UNUSED(sdrclk);
441 Q_UNUSED(nandclk);
442 Q_UNUSED(sdclk);
443 Q_UNUSED(mhaclk);
444 Q_UNUSED(mcaclk);
445 Q_UNUSED(pwmclk);
446 Q_UNUSED(i2c1clk);
447 Q_UNUSED(i2c2clk);
448}
449
450void ClockAnalyser::FillTreeRK27XX()
451{
452 soc_word_t value, value2, value3, value4;
453 soc_word_t bypass, clkr, clkf, clkod, pll_off;
454
455 QTreeWidgetItem *xtal_clk = AddClock(0, "xtal clk", 24000000);
456
457 // F = (Fref*F)/R/OD = (Fref*F)/R/OD
458 QTreeWidgetItem *arm_pll = 0;
459 if(ReadFieldOld("SCU", "PLLCON1", "ARM_PLL_BYPASS", bypass) &&
460 ReadFieldOld("SCU", "PLLCON1", "ARM_PLL_CLKR", clkr) &&
461 ReadFieldOld("SCU", "PLLCON1", "ARM_PLL_CLKF", clkf) &&
462 ReadFieldOld("SCU", "PLLCON1", "ARM_PLL_CLKOD", clkod) &&
463 ReadFieldOld("SCU", "PLLCON1", "ARM_PLL_POWERDOWN", pll_off))
464 {
465 arm_pll = AddClock(xtal_clk, "arm pll", pll_off ? DISABLED : FROM_PARENT,
466 bypass ? 1 : clkf+1, bypass ? 1 : (clkr+1)*(clkod+1));
467 }
468 else
469 {
470 arm_pll = AddClock(xtal_clk, "arm pll", INVALID);
471 }
472
473 QTreeWidgetItem *arm_clk = 0;
474 QTreeWidgetItem *hclk = 0;
475 QTreeWidgetItem *pclk = 0;
476 if(ReadFieldOld("SCU", "DIVCON1", "ARM_SLOW_MODE", value) &&
477 ReadFieldOld("SCU", "DIVCON1", "ARM_CLK_DIV", value2) &&
478 ReadFieldOld("SCU", "DIVCON1", "PCLK_CLK_DIV", value3))
479 {
480 arm_clk = AddClock(value ? xtal_clk : arm_pll, "arm clk", FROM_PARENT, 1, value2 ? 2 : 1);
481 hclk = AddClock(arm_clk, "hclk", FROM_PARENT, 1, value2 ? 1 : 2);
482 pclk = AddClock(hclk, "pclk", FROM_PARENT, 1, (1<<value3));
483 }
484 else
485 {
486 arm_clk = AddClock(xtal_clk, "arm_clk", INVALID);
487 hclk = AddClock(xtal_clk, "hclk", INVALID);
488 pclk = AddClock(xtal_clk, "pclk", INVALID);
489 }
490
491 QTreeWidgetItem *dsp_pll = 0;
492 if(ReadFieldOld("SCU", "PLLCON2", "DSP_PLL_BYPASS", bypass) &&
493 ReadFieldOld("SCU", "PLLCON2", "DSP_PLL_CLKR", clkr) &&
494 ReadFieldOld("SCU", "PLLCON2", "DSP_PLL_CLKF", clkf) &&
495 ReadFieldOld("SCU", "PLLCON2", "DSP_PLL_CLKOD", clkod) &&
496 ReadFieldOld("SCU", "PLLCON2", "DSP_PLL_POWERDOWN", pll_off))
497 {
498 dsp_pll = AddClock(xtal_clk, "dsp pll", pll_off ? DISABLED : FROM_PARENT,
499 bypass ? 1 : clkf+1, bypass ? 1 : (clkr+1)*(clkod+1));
500 }
501 else
502 {
503 dsp_pll = AddClock(xtal_clk, "dsp_pll", INVALID);
504 }
505
506 QTreeWidgetItem *dsp_clk = AddClock(dsp_pll, "dsp clk", FROM_PARENT);
507
508 QTreeWidgetItem *codec_pll = 0;
509 if(ReadFieldOld("SCU", "PLLCON3", "CODEC_PLL_BYPASS", bypass) &&
510 ReadFieldOld("SCU", "PLLCON3", "CODEC_PLL_CLKR", clkr) &&
511 ReadFieldOld("SCU", "PLLCON3", "CODEC_PLL_CLKF", clkf) &&
512 ReadFieldOld("SCU", "PLLCON3", "CODEC_PLL_CLKOD", clkod) &&
513 ReadFieldOld("SCU", "PLLCON3", "CODEC_PLL_POWERDOWN", pll_off))
514 {
515 codec_pll = AddClock(xtal_clk, "codec pll", pll_off ? DISABLED : FROM_PARENT,
516 bypass ? 1 : clkf+1, bypass ? 1 : (clkr+1)*(clkod+1));
517 }
518 else
519 {
520 codec_pll = AddClock(xtal_clk, "codec_pll", INVALID);
521 }
522
523 QTreeWidgetItem *codec_clk = 0;
524 if(ReadFieldOld("SCU", "DIVCON1", "CODEC_CLK_SRC", value) &&
525 ReadFieldOld("SCU", "DIVCON1", "CODEC_CLK_DIV", value2))
526 {
527 codec_clk = AddClock(value ? xtal_clk : codec_pll, "codec clk", FROM_PARENT, 1, value ? 1 : (value2 + 1));
528 }
529 else
530 {
531 codec_clk = AddClock(xtal_clk, "codec_clk", INVALID);
532 }
533
534 QTreeWidgetItem *lsadc_clk = 0;
535 if(ReadFieldOld("SCU", "DIVCON1", "LSADC_CLK_DIV", value))
536 {
537 lsadc_clk = AddClock(pclk, "lsadc clk", FROM_PARENT, 1, (value+1));
538 }
539 else
540 {
541 lsadc_clk = AddClock(xtal_clk, "lsadc clk", INVALID);
542 }
543
544 QTreeWidgetItem *lcdc_clk = 0;
545 if(ReadFieldOld("SCU", "DIVCON1", "LCDC_CLK", value) &&
546 ReadFieldOld("SCU", "DIVCON1", "LCDC_CLK_DIV", value2) &&
547 ReadFieldOld("SCU", "DIVCON1", "LCDC_CLK_DIV_SRC", value3))
548 {
549 if(value)
550 {
551 lcdc_clk = AddClock(xtal_clk, "lcdc clk", FROM_PARENT);
552 }
553 else
554 {
555 if(value3 == 0)
556 lcdc_clk = AddClock(arm_pll, "lcdc clk", FROM_PARENT, 1, value2+1);
557 else if(value3 == 1)
558 lcdc_clk = AddClock(dsp_pll, "lcdc clk", FROM_PARENT, 1, value2+1);
559 else
560 lcdc_clk = AddClock(codec_pll, "lcdc clk", FROM_PARENT, 1, value2+1);
561 }
562 }
563 else
564 {
565 lcdc_clk = AddClock(xtal_clk, "lcdc clk", INVALID);
566 }
567
568 QTreeWidgetItem *pwm0_clk = 0;
569 if(ReadFieldOld("PWM0", "LRC", "TR", value) &&
570 ReadFieldOld("PWM0", "CTRL", "PRESCALE", value3) &&
571 ReadFieldOld("PWM0", "CTRL", "PWM_EN", value4))
572 {
573 pwm0_clk = AddClock(pclk, "pwm0 clk", value4 ? FROM_PARENT : DISABLED, 1, 2*value*(1<<value3));
574 }
575 else
576 {
577 pwm0_clk = AddClock(xtal_clk, "pwm0 clk", INVALID);
578 }
579
580 QTreeWidgetItem *pwm1_clk = 0;
581 if(ReadFieldOld("PWM1", "LRC", "TR", value) &&
582 ReadFieldOld("PWM1", "CTRL", "PRESCALE", value3) &&
583 ReadFieldOld("PWM1", "CTRL", "PWM_EN", value4))
584 {
585 pwm1_clk = AddClock(pclk, "pwm1 clk", value4 ? FROM_PARENT : DISABLED, 1, 2*value*(1<<value3));
586 }
587 else
588 {
589 pwm1_clk = AddClock(xtal_clk, "pwm1 clk", INVALID);
590 }
591
592 QTreeWidgetItem *pwm2_clk = 0;
593 if(ReadFieldOld("PWM2", "LRC", "TR", value) &&
594 ReadFieldOld("PWM2", "CTRL", "PRESCALE", value3) &&
595 ReadFieldOld("PWM2", "CTRL", "PWM_EN", value4))
596 {
597 pwm2_clk = AddClock(pclk, "pwm2 clk", value4 ? FROM_PARENT : DISABLED, 1, 2*value*(1<<value3));
598 }
599 else
600 {
601 pwm2_clk = AddClock(xtal_clk, "pwm2 clk", INVALID);
602 }
603
604 QTreeWidgetItem *pwm3_clk = 0;
605 if(ReadFieldOld("PWM3", "LRC", "TR", value) &&
606 ReadFieldOld("PWM3", "CTRL", "PRESCALE", value3) &&
607 ReadFieldOld("PWM3", "CTRL", "PWM_EN", value4))
608 {
609 pwm3_clk = AddClock(pclk, "pwm3", value4 ? FROM_PARENT : DISABLED, 1, 2*value*(1<<value3));
610 }
611 else
612 {
613 pwm3_clk = AddClock(xtal_clk, "pwm3 clk", INVALID);
614 }
615
616 QTreeWidgetItem *sdmmc_clk = 0;
617 if(ReadFieldOld("SD", "CTRL", "DIVIDER", value))
618 {
619 sdmmc_clk = AddClock(pclk, "sd clk", FROM_PARENT, 1, value+1);
620 }
621 else
622 {
623 sdmmc_clk = AddClock(xtal_clk, "sd clk", INVALID);
624 }
625
626 Q_UNUSED(dsp_clk);
627 Q_UNUSED(codec_clk);
628 Q_UNUSED(lsadc_clk);
629 Q_UNUSED(lcdc_clk);
630 Q_UNUSED(pwm0_clk);
631 Q_UNUSED(pwm1_clk);
632 Q_UNUSED(pwm2_clk);
633 Q_UNUSED(pwm3_clk);
634 Q_UNUSED(sdmmc_clk);
635}
636
637void ClockAnalyser::FillTreeIMX233()
638{
639 /* work for stmp3700 and imx233 */
640 soc_word_t value, value2, value3;
641
642 QTreeWidgetItem *ring_osc = 0;
643 if(ReadFieldOld("POWER", "MINPWR", "ENABLE_OSC", value))
644 ring_osc = AddClock(0, "ring_clk24m", value ? 24000000 : DISABLED);
645 else
646 ring_osc = AddClock(0, "ring_clk24m", INVALID);
647 QTreeWidgetItem *xtal_osc = 0;
648 if(ReadFieldOld("POWER", "MINPWR", "PWD_XTAL24", value))
649 xtal_osc = AddClock(0, "xtal_clk24m", value ? DISABLED : 24000000);
650 else
651 xtal_osc = AddClock(0, "xtal_clk24m", INVALID);
652 QTreeWidgetItem *ref_xtal = 0;
653 if(ReadFieldOld("POWER", "MINPWR", "SELECT_OSC", value))
654 ref_xtal = AddClock(value ? ring_osc : xtal_osc, "ref_xtal", FROM_PARENT);
655 else
656 ref_xtal = AddClock(0, "ref_xtal", INVALID);
657
658 QTreeWidgetItem *ref_pll = 0;
659 if(ReadFieldOld("CLKCTRL", "PLLCTRL0", "POWER", value))
660 ref_pll = AddClock(ref_xtal, "ref_pll", FROM_PARENT, 20);
661 else
662 ref_pll = AddClock(0, "ref_pll", INVALID);
663
664 QTreeWidgetItem *ref_io = 0;
665 if(ReadFieldOld("CLKCTRL", "FRAC", "CLKGATEIO", value) &&
666 ReadFieldOld("CLKCTRL", "FRAC", "IOFRAC", value2))
667 ref_io = AddClock(ref_pll, "ref_io", value ? DISABLED : FROM_PARENT, 18, value2);
668 else
669 ref_io = AddClock(ref_pll, "ref_io", INVALID);
670
671 QTreeWidgetItem *ref_pix = 0;
672 if(ReadFieldOld("CLKCTRL", "FRAC", "CLKGATEPIX", value) &&
673 ReadFieldOld("CLKCTRL", "FRAC", "PIXFRAC", value2))
674 ref_pix = AddClock(ref_pll, "ref_pix", value ? DISABLED : FROM_PARENT, 18, value2);
675 else
676 ref_pix = AddClock(ref_pll, "ref_pix", INVALID);
677
678 QTreeWidgetItem *ref_emi = 0;
679 if(ReadFieldOld("CLKCTRL", "FRAC", "CLKGATEEMI", value) &&
680 ReadFieldOld("CLKCTRL", "FRAC", "EMIFRAC", value2))
681 ref_emi = AddClock(ref_pll, "ref_emi", value ? DISABLED : FROM_PARENT, 18, value2);
682 else
683 ref_emi = AddClock(ref_pll, "ref_emi", INVALID);
684
685 QTreeWidgetItem *ref_cpu = 0;
686 if(ReadFieldOld("CLKCTRL", "FRAC", "CLKGATECPU", value) &&
687 ReadFieldOld("CLKCTRL", "FRAC", "CPUFRAC", value2))
688 ref_cpu = AddClock(ref_pll, "ref_cpu", value ? DISABLED : FROM_PARENT, 18, value2);
689 else
690 ref_cpu = AddClock(ref_pll, "ref_cpu", INVALID);
691
692 QTreeWidgetItem *clk_p = 0;
693 if(ReadFieldOld("CLKCTRL", "CLKSEQ", "BYPASS_CPU", value))
694 {
695 if(!value)
696 {
697 if(ReadFieldOld("CLKCTRL", "CPU", "DIV_CPU", value2))
698 clk_p = AddClock(ref_cpu, "clk_p", FROM_PARENT, 1, value2);
699 else
700 clk_p = AddClock(ref_cpu, "clk_p", INVALID);
701 }
702 else
703 {
704 if(ReadFieldOld("CLKCTRL", "CPU", "DIV_XTAL_FRAC_EN", value) &&
705 ReadFieldOld("CLKCTRL", "CPU", "DIV_XTAL", value2))
706 clk_p = AddClock(ref_xtal, "clk_p", FROM_PARENT, value ? 1024 : 1, value2);
707 else
708 clk_p = AddClock(ref_xtal, "clk_p", INVALID);
709 }
710 }
711 else
712 clk_p = AddClock(ref_xtal, "clk_p", INVALID);
713
714 QTreeWidgetItem *clk_h = 0;
715 if(ReadFieldOld("CLKCTRL", "HBUS", "DIV_FRAC_EN", value) &&
716 ReadFieldOld("CLKCTRL", "HBUS", "DIV", value2))
717 clk_h = AddClock(clk_p, "clk_h", FROM_PARENT, value ? 32 : 1, value2);
718 else
719 clk_h = AddClock(clk_p, "clk_h", INVALID);
720
721 QTreeWidgetItem *clk_x = 0;
722 if(ReadFieldOld("CLKCTRL", "XBUS", "DIV", value))
723 clk_x = AddClock(ref_xtal, "clk_x", FROM_PARENT, 1, value);
724 else
725 clk_x = AddClock(ref_xtal, "clk_x", INVALID);
726
727 if(ReadFieldOld("CLKCTRL", "XTAL", "UART_CLK_GATE", value))
728 AddClock(ref_xtal, "clk_uart", value ? DISABLED : FROM_PARENT);
729 else
730 AddClock(ref_xtal, "clk_uart", INVALID);
731
732 if(ReadFieldOld("CLKCTRL", "XTAL", "FILT_CLK24M_GATE", value))
733 AddClock(ref_xtal, "clk_filt24m", value ? DISABLED : FROM_PARENT);
734 else
735 AddClock(ref_xtal, "clk_filt24m", INVALID);
736
737 if(ReadFieldOld("CLKCTRL", "XTAL", "PWM_CLK24M_GATE", value))
738 AddClock(ref_xtal, "clk_pwm24m", value ? DISABLED : FROM_PARENT);
739 else
740 AddClock(ref_xtal, "clk_pwm24m", INVALID);
741
742 if(ReadFieldOld("CLKCTRL", "XTAL", "DRI_CLK24M_GATE", value))
743 AddClock(ref_xtal, "clk_dri24m", value ? DISABLED : FROM_PARENT);
744 else
745 AddClock(ref_xtal, "clk_dri24m", INVALID);
746
747 if(ReadFieldOld("CLKCTRL", "XTAL", "DIGCTRL_CLK1M_GATE", value))
748 AddClock(ref_xtal, "clk_1m", value ? DISABLED : FROM_PARENT, 1, 24);
749 else
750 AddClock(ref_xtal, "clk_1m", INVALID);
751
752 QTreeWidgetItem *clk_32k = 0;
753 if(ReadFieldOld("CLKCTRL", "XTAL", "TIMROT_CLK32K_GATE", value))
754 clk_32k = AddClock(ref_xtal, "clk_32k", value ? DISABLED : FROM_PARENT, 1, 750);
755 else
756 clk_32k = AddClock(ref_xtal, "clk_32k", INVALID);
757
758 AddClock(clk_32k, "clk_adc", FROM_PARENT, 1, 16);
759
760 if(ReadFieldOld("CLKCTRL", "CLKSEQ", "BYPASS_PIX", value) &&
761 ReadFieldOld("CLKCTRL", "PIX", "DIV", value2))
762 AddClock(value ? ref_xtal : ref_pix, "clk_pix", FROM_PARENT, 1, value2);
763 else
764 AddClock(ref_xtal, "clk_p", INVALID);
765
766 QTreeWidgetItem *clk_ssp = 0;
767 if(ReadFieldOld("CLKCTRL", "CLKSEQ", "BYPASS_SSP", value) &&
768 ReadFieldOld("CLKCTRL", "SSP", "DIV", value2) &&
769 ReadFieldOld("CLKCTRL", "SSP", "CLKGATE", value3))
770 clk_ssp = AddClock(value ? ref_xtal : ref_io, "clk_ssp", value3 ? DISABLED : FROM_PARENT, 1, value2);
771 else
772 clk_ssp = AddClock(ref_xtal, "clk_ssp", INVALID);
773
774 if(ReadFieldOld("SSP[1]", "TIMING", "CLOCK_DIVIDE", value) &&
775 ReadFieldOld("SSP[1]", "TIMING", "CLOCK_RATE", value2) &&
776 ReadFieldOld("SSP[1]", "CTRL0", "CLKGATE", value3))
777 AddClock(clk_ssp, "clk_ssp1", value3 ? DISABLED : FROM_PARENT, 1, value * (1 + value2));
778 else
779 AddClock(clk_ssp, "clk_ssp1", INVALID);
780
781 if(ReadFieldOld("SSP[2]", "TIMING", "CLOCK_DIVIDE", value) &&
782 ReadFieldOld("SSP[2]", "TIMING", "CLOCK_RATE", value2) &&
783 ReadFieldOld("SSP[2]", "CTRL0", "CLKGATE", value3))
784 AddClock(clk_ssp, "clk_ssp2", value3 ? DISABLED : FROM_PARENT, 1, value * (1 + value2));
785 else
786 AddClock(clk_ssp, "clk_ssp2", INVALID);
787
788 QTreeWidgetItem *clk_gpmi = 0;
789 if(ReadFieldOld("CLKCTRL", "CLKSEQ", "BYPASS_GPMI", value) &&
790 ReadFieldOld("CLKCTRL", "GPMI", "DIV", value2) &&
791 ReadFieldOld("CLKCTRL", "GPMI", "CLKGATE", value3))
792 clk_gpmi = AddClock(value ? ref_xtal : ref_io, "clk_gpmi", value3 ? DISABLED : FROM_PARENT, 1, value2);
793 else
794 clk_gpmi = AddClock(ref_xtal, "clk_p", INVALID);
795
796 if(ReadFieldOld("CLKCTRL", "CLKSEQ", "BYPASS_EMI", value))
797 {
798 if(!value)
799 {
800 if(ReadFieldOld("CLKCTRL", "EMI", "DIV_EMI", value2) &&
801 ReadFieldOld("CLKCTRL", "EMI", "CLKGATE", value3))
802 AddClock(ref_emi, "clk_emi", value3 ? DISABLED : FROM_PARENT, 1, value2);
803 else
804 AddClock(ref_emi, "clk_emi", INVALID);
805 }
806 else
807 {
808 if(ReadFieldOld("CLKCTRL", "EMI", "DIV_XTAL", value2) &&
809 ReadFieldOld("CLKCTRL", "EMI", "CLKGATE", value3))
810 AddClock(ref_xtal, "clk_emi", value3 ? DISABLED : FROM_PARENT, 1, value2);
811 else
812 AddClock(ref_xtal, "clk_emi", INVALID);
813 }
814 }
815 else
816 clk_p = AddClock(ref_xtal, "clk_emi", INVALID);
817
818 QTreeWidgetItem *ref_vid = AddClock(ref_pll, "clk_vid", FROM_PARENT);
819
820 if(ReadFieldOld("CLKCTRL", "TV", "CLK_TV108M_GATE", value) &&
821 ReadFieldOld("CLKCTRL", "TV", "CLK_TV_GATE", value2))
822 {
823 QTreeWidgetItem *clk_tv108m = AddClock(ref_vid, "clk_tv108m", value ? DISABLED : FROM_PARENT, 1, 4);
824 AddClock(clk_tv108m, "clk_tv54m", value2 ? DISABLED : FROM_PARENT, 1, 2);
825 AddClock(clk_tv108m, "clk_tv27m", value2 ? DISABLED : FROM_PARENT, 1, 4);
826 }
827
828 if(ReadFieldOld("CLKCTRL", "PLLCTRL0", "EN_USB_CLKS", value))
829 AddClock(ref_pll, "utmi_clk480m", value ? FROM_PARENT : DISABLED);
830 else
831 AddClock(ref_pll, "utmi_clk480m", INVALID);
832
833 QTreeWidgetItem *xtal_clk32k = 0;
834 if(ReadFieldOld("RTC", "PERSISTENT0", "XTAL32_FREQ", value) &&
835 ReadFieldOld("RTC", "PERSISTENT0", "XTAL32KHZ_PWRUP", value2))
836 xtal_clk32k = AddClock(0, "xtal_clk32k", value2 == 0 ? DISABLED : value ? 32000 : 32768);
837 else
838 xtal_clk32k = AddClock(0, "xtal_clk32k", INVALID);
839
840 if(ReadFieldOld("RTC", "PERSISTENT0", "CLOCKSOURCE", value))
841 AddClock(value ? xtal_clk32k : ref_xtal, "clk_rtc32k", FROM_PARENT, 1, value ? 1 : 768);
842 else
843 AddClock(ref_xtal, "clk_rtc32k", INVALID);
844
845 Q_UNUSED(clk_x);
846 Q_UNUSED(clk_gpmi);
847 Q_UNUSED(clk_h);
848}
849
850static TmplAnalyserFactory< ClockAnalyser > g_clock_factory(true, "Clock Analyser");
851
852/**
853 * EMI analyser
854 */
855EmiAnalyser::EmiAnalyser(const soc_desc::soc_ref_t& soc, IoBackend *backend)
856 :AnalyserEx(soc, backend)
857{
858 m_display_mode = DisplayCycles;
859 m_group = new QGroupBox("EMI Analyser");
860 QVBoxLayout *layout = new QVBoxLayout;
861 m_group->setLayout(layout);
862 m_panel = new QToolBox;
863 m_display_selector = new QComboBox;
864 m_display_selector->addItem("Cycles", DisplayCycles);
865 m_display_selector->addItem("Raw Hexadecimal", DisplayRawHex);
866 m_display_selector->addItem("Time", DisplayTime);
867 QHBoxLayout *line_layout = new QHBoxLayout;
868 line_layout->addWidget(new QLabel("Display Mode:"));
869 line_layout->addWidget(m_display_selector);
870 m_emi_freq_label = new QLineEdit;
871 m_emi_freq_label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
872 m_emi_freq_label->setReadOnly(true);
873 m_emi_size_label = new QLineEdit;
874 m_emi_size_label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
875 m_emi_size_label->setReadOnly(true);
876 line_layout->addStretch();
877 line_layout->addWidget(new QLabel("Size:"));
878 line_layout->addWidget(m_emi_size_label);
879 line_layout->addWidget(new QLabel("MiB"));
880 line_layout->addStretch();
881 line_layout->addWidget(new QLabel("Frequency:"));
882 line_layout->addWidget(m_emi_freq_label);
883 line_layout->addWidget(new QLabel("MHz"));
884 line_layout->addStretch();
885 layout->addLayout(line_layout);
886 layout->addWidget(m_panel);
887
888 connect(m_display_selector, SIGNAL(currentIndexChanged(int)), this,
889 SLOT(OnChangeDisplayMode(int)));
890
891 FillTable();
892}
893
894EmiAnalyser::~EmiAnalyser()
895{
896 delete m_group;
897}
898
899QWidget *EmiAnalyser::GetWidget()
900{
901 return m_group;
902}
903
904bool EmiAnalyser::SupportSoc(const QString& soc_name)
905{
906 return soc_name == "imx233" || soc_name == "stmp3700";
907}
908
909void EmiAnalyser::OnChangeDisplayMode(int index)
910{
911 if(index == -1)
912 return;
913 m_display_mode = (DisplayMode)m_display_selector->itemData(index).toInt();
914 int idx = m_panel->currentIndex();
915 FillTable();
916 m_panel->setCurrentIndex(idx);
917}
918
919void EmiAnalyser::NewGroup(const QString& name)
920{
921 QTableWidget *table = new QTableWidget;
922 table->setColumnCount(3);
923 table->setHorizontalHeaderItem(0, new QTableWidgetItem("Name"));
924 table->setHorizontalHeaderItem(1, new QTableWidgetItem("Value"));
925 table->setHorizontalHeaderItem(2, new QTableWidgetItem("Comment"));
926 table->verticalHeader()->setVisible(false);
927 table->horizontalHeader()->setStretchLastSection(true);
928 m_panel->addItem(table, name);
929}
930
931void EmiAnalyser::AddLine(const QString& name, int value, const QString& unit, const QString& comment)
932{
933 QTableWidget *table = dynamic_cast< QTableWidget* >(m_panel->widget(m_panel->count() - 1));
934 int row = table->rowCount();
935 table->setRowCount(row + 1);
936 table->setItem(row, 0, new QTableWidgetItem(name));
937 QString val;
938 if(value == INVALID)
939 val = "<invalid>";
940 else if(value == NONE)
941 val = unit;
942 else if(m_display_mode == DisplayRawHex && unit.size() == 0)
943 val = QString("0x%1").arg(value, 0, 16);
944 else
945 val = QString("%1%2").arg(value).arg(unit);
946 table->setItem(row, 1, new QTableWidgetItem(val));
947 table->item(row, 1)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
948 table->setItem(row, 2, new QTableWidgetItem(comment));
949 table->resizeColumnToContents(0);
950 table->resizeColumnToContents(1);
951}
952
953void EmiAnalyser::AddCycleLine(const QString& name, unsigned raw_val, float val,
954 int digits, const QString& comment)
955{
956 if(m_display_mode == DisplayCycles)
957 {
958 QString str;
959 if(digits == 0)
960 str = QString("%1").arg((int)val);
961 else
962 str = QString("%1").arg(val, 0, 'f', digits);
963 str += " cycles";
964 AddLine(name, NONE, str, comment);
965 }
966 else if(m_display_mode == DisplayRawHex)
967 {
968 QString str = QString("0x%1").arg(raw_val, 0, 16);
969 AddLine(name, NONE, str, comment);
970 }
971 else if(m_display_mode == DisplayTime && m_emi_freq != 0)
972 {
973 float cycle_time_ns = 1000000000.0 / m_emi_freq;
974 val *= cycle_time_ns;
975 QString str;
976 if(val >= 1000)
977 str = QString::fromWCharArray(L"%1 µs").arg(val / 1000.0, 0, 'f', 2);
978 else
979 str = QString("%1 ns").arg(val, 0, 'f', 2);
980 AddLine(name, NONE, str, comment);
981 }
982 else
983 AddLine(name, raw_val, " cycles", comment);
984}
985
986void EmiAnalyser::FillTable()
987{
988 while(m_panel->count() > 0)
989 m_panel->removeItem(0);
990 soc_word_t value;
991
992 m_emi_freq = 0;
993 if(ReadFieldOld("CLKCTRL", "CLKSEQ", "BYPASS_EMI", value))
994 {
995 bool ret;
996 if(value)
997 {
998 m_emi_freq = 24000000;
999 ret = ReadFieldOld("CLKCTRL", "EMI", "DIV_XTAL", value);
1000 }
1001 else
1002 {
1003 m_emi_freq = 480000000;
1004 if(ReadFieldOld("CLKCTRL", "FRAC", "EMIFRAC", value))
1005 m_emi_freq = 18 * (int64_t)m_emi_freq / value;
1006 else
1007 m_emi_freq = 0;
1008 ret = ReadFieldOld("CLKCTRL", "EMI", "DIV_EMI", value);
1009 }
1010 if(ret)
1011 m_emi_freq /= value;
1012 else
1013 m_emi_freq = 0;
1014 }
1015
1016 m_emi_freq_label->setText(QString().sprintf("%.3f", m_emi_freq / 1000000.0));
1017
1018 soc_word_t rows, columns, cs_map;
1019 if(ReadFieldOld("DRAM", "CTL14", "CS_MAP", cs_map) &&
1020 ReadFieldOld("DRAM", "CTL10", "ADDR_PINS", rows) &&
1021 ReadFieldOld("DRAM", "CTL11", "COLUMN_SIZE", columns))
1022 {
1023 rows = 13 - rows;
1024 columns = 12 - columns;
1025 soc_word_t banks = 4;
1026 soc_word_t chips = __builtin_popcount(cs_map);
1027 unsigned long size = 2 * (1 << (rows + columns)) * chips * banks;
1028 m_emi_size_label->setText(QString().sprintf("%lu", (unsigned long)size / 1024 / 1024));
1029 }
1030 else
1031 m_emi_size_label->setText("<invalid>");
1032
1033 NewGroup("Control Parameters");
1034 if(ReadFieldOld("EMI", "CTRL", "PORT_PRIORITY_ORDER", value))
1035 {
1036 QStringList ports;
1037 ports << "AXI0" << "AHB1" << "AHB2" << "AHB3";
1038 QString order;
1039 order += ports[value / 6];
1040 ports.erase(ports.begin() + value / 6);
1041 int ord[6][3] = { {0, 1, 2}, {2, 0, 1}, {1, 2, 0}, {2, 1, 0}, {1, 0, 2}, {0, 2, 1} };
1042 for(int i = 0; i < 3; i++)
1043 order += ", " + ports[ord[value % 6][i]];
1044 AddLine("Port Priority Order", value, "", order);
1045 }
1046
1047 if(ReadFieldOld("EMI", "CTRL", "MEM_WIDTH", value))
1048 AddLine("Memory Width", value ? 16 : 8, "-bit");
1049
1050 if(ReadFieldOld("DRAM", "CTL03", "AP", value))
1051 AddLine("Auto Pre-Charge", NONE, value ? "Yes" : "No");
1052
1053 bool bypass_mode = false;
1054 if(ReadFieldOld("DRAM", "CTL04", "DLL_BYPASS_MODE", value))
1055 {
1056 bypass_mode = value == 1;
1057 AddLine("DLL Bypass Mode", NONE, value ? "Yes" : "No");
1058 }
1059
1060 if(ReadFieldOld("DRAM", "CTL05", "EN_LOWPOWER_MODE", value))
1061 AddLine("Low Power Mode", NONE, value ? "Enabled" : "Disabled");
1062
1063 if(ReadFieldOld("DRAM", "CTL08", "SREFRESH", value))
1064 AddLine("Self Refresh", NONE, value ? "Yes" : "No");
1065
1066 if(ReadFieldOld("DRAM", "CTL08", "SDR_MODE", value))
1067 AddLine("Mode", NONE, value ? "SDR" : "DDR");
1068
1069 if(ReadFieldOld("DRAM", "CTL10", "ADDR_PINS", value))
1070 AddLine("Address Pins", 13 - value, "");
1071
1072 if(ReadFieldOld("DRAM", "CTL11", "COLUMN_SIZE", value))
1073 AddLine("Column Size", 12 - value, "-bit");
1074
1075 if(ReadFieldOld("DRAM", "CTL11", "CASLAT", value))
1076 AddLine("Encoded CAS", value, "", "Memory device dependent");
1077
1078 if(ReadFieldOld("DRAM", "CTL14", "CS_MAP", value))
1079 {
1080 QString v;
1081 for(int i = 0; i < 4; i++)
1082 if(value & (1 << i))
1083 {
1084 if(v.size() != 0)
1085 v += " ";
1086 v += QString("%1").arg(i);
1087 }
1088 AddLine("Chip Select Pins", NONE, v, "");
1089 }
1090
1091 if(ReadFieldOld("DRAM", "CTL37", "TREF_ENABLE", value))
1092 AddLine("Refresh Commands", NONE, value ? "Enabled" : "Disabled", "Issue self-refresh every TREF cycles");
1093
1094 NewGroup("Frequency Parameters");
1095
1096 if(ReadFieldOld("DRAM", "CTL13", "CASLAT_LIN_GATE", value))
1097 {
1098 if(value >= 3 && value <= 10 && value != 9)
1099 {
1100 float v = (value / 2) + 0.5 * (value % 2);
1101 AddCycleLine("CAS Gate", value, v, 1, "");
1102 }
1103 else
1104 AddLine("CAS Gate", NONE, "Reserved", "Reserved value");
1105 }
1106 if(ReadFieldOld("DRAM", "CTL13", "CASLAT_LIN", value))
1107 {
1108 if(value >= 3 && value <= 10 && value != 9)
1109 {
1110 float v = (value / 2) + 0.5 * (value % 2);
1111 AddCycleLine("CAS Latency", value, v, 1, "");
1112 }
1113 else
1114 AddLine("CAS Latency", NONE, "Reserved", "Reserved value");
1115 }
1116
1117 if(ReadFieldOld("DRAM", "CTL12", "TCKE", value))
1118 AddCycleLine("tCKE", value, value, 0, "Minimum CKE pulse width");
1119
1120 if(ReadFieldOld("DRAM", "CTL15", "TDAL", value))
1121 AddCycleLine("tDAL", value, value, 0, "Auto pre-charge write recovery time");
1122
1123 if(ReadFieldOld("DRAM", "CTL31", "TDLL", value))
1124 AddCycleLine("tDLL", value, value, 0, "DLL lock time");
1125
1126 if(ReadFieldOld("DRAM", "CTL10", "TEMRS", value))
1127 AddCycleLine("tEMRS", value, value, 0, "Extended mode parameter set time");
1128
1129 if(ReadFieldOld("DRAM", "CTL34", "TINIT", value))
1130 AddCycleLine("tINIT", value, value, 0, "Initialisation time");
1131
1132 if(ReadFieldOld("DRAM", "CTL16", "TMRD", value))
1133 AddCycleLine("tMRD", value, value, 0, "Mode register set command time");
1134
1135 if(ReadFieldOld("DRAM", "CTL40", "TPDEX", value))
1136 AddCycleLine("tPDEX", value, value, 0, "Power down exit time");
1137
1138 if(ReadFieldOld("DRAM", "CTL32", "TRAS_MAX", value))
1139 AddCycleLine("tRAS Max", value, value, 0, "Maximum row activate time");
1140
1141 if(ReadFieldOld("DRAM", "CTL20", "TRAS_MIN", value))
1142 AddCycleLine("tRAS Min", value, value, 0, "Minimum row activate time");
1143
1144 if(ReadFieldOld("DRAM", "CTL17", "TRC", value))
1145 AddCycleLine("tRC", value, value, 0, "Activate to activate delay (same bank)");
1146
1147 if(ReadFieldOld("DRAM", "CTL20", "TRCD_INT", value))
1148 AddCycleLine("tRCD", value, value, 0, "RAS to CAS");
1149
1150 if(ReadFieldOld("DRAM", "CTL26", "TREF", value))
1151 AddCycleLine("tREF", value, value, 0, "Refresh to refresh time");
1152
1153 if(ReadFieldOld("DRAM", "CTL21", "TRFC", value))
1154 AddCycleLine("tRFC", value, value, 0, "Refresh command time");
1155
1156 if(ReadFieldOld("DRAM", "CTL15", "TRP", value))
1157 AddCycleLine("tRP", value, value, 0, "Pre-charge command time");
1158
1159 if(ReadFieldOld("DRAM", "CTL12", "TRRD", value))
1160 AddCycleLine("tRRD", value, value, 0, "Activate to activate delay (different banks)");
1161
1162 if(ReadFieldOld("DRAM", "CTL12", "TWR_INT", value))
1163 AddCycleLine("tWR", value, value, 0, "Write recovery time");
1164
1165 if(ReadFieldOld("DRAM", "CTL13", "TWTR", value))
1166 AddCycleLine("tWTR", value, value, 0, "Write to read delay");
1167
1168 if(ReadFieldOld("DRAM", "CTL32", "TXSNR", value))
1169 AddCycleLine("tXSNR", value, value, 0, "");
1170
1171 if(ReadFieldOld("DRAM", "CTL33", "TXSR", value))
1172 AddCycleLine("tXSR", value, value, 0, "Self-refresh exit time");
1173
1174 NewGroup("DLL Parameters");
1175
1176 if(bypass_mode)
1177 {
1178 if(ReadFieldOld("DRAM", "CTL19", "DLL_DQS_DELAY_BYPASS_0", value))
1179 AddLine("DLL DQS Delay 0", value, "", "In 1/128 fraction of a cycle (bypass mode)");
1180
1181 if(ReadFieldOld("DRAM", "CTL19", "DLL_DQS_DELAY_BYPASS_0", value))
1182 AddLine("DLL DQS Delay 1", value, "", "In 1/128 fraction of a cycle (bypass mode)");
1183
1184 if(ReadFieldOld("DRAM", "CTL19", "DQS_OUT_SHIFT_BYPASS", value))
1185 AddLine("DQS Out Delay", value, "", "(bypass mode)");
1186
1187 if(ReadFieldOld("DRAM", "CTL20", "WR_DQS_SHIFT_BYPASS", value))
1188 AddLine("DQS Write Delay", value, "", "(bypass mode)");
1189 }
1190 else
1191 {
1192 if(ReadFieldOld("DRAM", "CTL17", "DLL_START_POINT", value))
1193 AddLine("DLL Start Point", value, "", "Initial delay count");
1194
1195 if(ReadFieldOld("DRAM", "CTL17", "DLL_INCREMENT", value))
1196 AddLine("DLL Increment", value, "", "Delay increment");
1197
1198 if(ReadFieldOld("DRAM", "CTL18", "DLL_DQS_DELAY_0", value))
1199 AddLine("DLL DQS Delay 0", value, "", "In 1/128 fraction of a cycle");
1200
1201 if(ReadFieldOld("DRAM", "CTL18", "DLL_DQS_DELAY_1", value))
1202 AddLine("DLL DQS Delay 1", value, "", "In 1/128 fraction of a cycle");
1203
1204 if(ReadFieldOld("DRAM", "CTL19", "DQS_OUT_SHIFT", value))
1205 AddLine("DQS Out Delay", value, "", "");
1206
1207 if(ReadFieldOld("DRAM", "CTL20", "WR_DQS_SHIFT", value))
1208 AddLine("DQS Write Delay", value, "", "");
1209 }
1210
1211}
1212
1213static TmplAnalyserFactory< EmiAnalyser > g_emi_factory(true, "EMI Analyser");
1214
1215/**
1216 * Pin analyser
1217 */
1218
1219namespace pin_desc
1220{
1221#include "../../imxtools/misc/map.h"
1222}
1223
1224PinAnalyser::PinAnalyser(const soc_desc::soc_ref_t& soc, IoBackend *backend)
1225 :AnalyserEx(soc, backend)
1226{
1227 m_group = new QGroupBox("Pin Analyser");
1228 QVBoxLayout *layout = new QVBoxLayout;
1229 m_group->setLayout(layout);
1230 QLabel *label = new QLabel("Package:");
1231 m_package_edit = new QLineEdit;
1232 m_package_edit->setReadOnly(true);
1233 m_package_edit->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
1234 QHBoxLayout *hlayout = new QHBoxLayout;
1235 hlayout->addStretch();
1236 hlayout->addWidget(label);
1237 hlayout->addWidget(m_package_edit);
1238 hlayout->addStretch();
1239 layout->addLayout(hlayout);
1240 m_panel = new QToolBox;
1241 layout->addWidget(m_panel);
1242
1243 FillList();
1244}
1245
1246PinAnalyser::~PinAnalyser()
1247{
1248 delete m_group;
1249}
1250
1251QWidget *PinAnalyser::GetWidget()
1252{
1253 return m_group;
1254}
1255
1256bool PinAnalyser::SupportSoc(const QString& soc_name)
1257{
1258 return soc_name == "imx233" || soc_name == "stmp3700";
1259}
1260
1261void PinAnalyser::FillList()
1262{
1263 soc_word_t value;
1264
1265 while(m_panel->count() > 0)
1266 m_panel->removeItem(0);
1267
1268 const char *package_type[8] =
1269 {
1270 "bga169", "bga100", "lqfp100", "lqfp128", 0, 0, 0, 0
1271 };
1272
1273 if(!ReadFieldOld("DIGCTL", "STATUS", "PACKAGE_TYPE", value))
1274 {
1275 m_package_edit->setText("<read error>");
1276 return;
1277 }
1278 if(value >= 8 || package_type[value] == NULL)
1279 {
1280 m_package_edit->setText("<unknown package>");
1281 return;
1282 }
1283 const char *package = package_type[value];
1284 m_package_edit->setText(package);
1285 pin_desc::bank_map_t *map = NULL;
1286 for(size_t i = 0; i < sizeof(pin_desc::socs) / sizeof(pin_desc::socs[0]); i++)
1287 if(QString(pin_desc::socs[i].soc) == m_io_backend->GetSocName() &&
1288 QString(pin_desc::socs[i].ver) == package)
1289 map = pin_desc::socs[i].map;
1290 if(map == NULL)
1291 {
1292 m_package_edit->setText(QString("%1 (no map available)").arg(package));
1293 return;
1294 }
1295
1296 QMap< unsigned, QColor > color_map;
1297 color_map[PIN_GROUP_EMI] = QColor(255, 255, 64);
1298 color_map[PIN_GROUP_GPIO] = QColor(171, 214, 230);
1299 color_map[PIN_GROUP_I2C] = QColor(191, 191, 255);
1300 color_map[PIN_GROUP_JTAG] = QColor(238, 75, 21);
1301 color_map[PIN_GROUP_PWM] = QColor(255, 236, 179);
1302 color_map[PIN_GROUP_SPDIF] = QColor(174, 235, 63);
1303 color_map[PIN_GROUP_TIMROT] = QColor(255, 112, 237);
1304 color_map[PIN_GROUP_AUART] = QColor(94, 255, 128);
1305 color_map[PIN_GROUP_ETM] = QColor(168, 53, 14);
1306 color_map[PIN_GROUP_GPMI] = QColor(255, 211, 147);
1307 color_map[PIN_GROUP_IrDA] = QColor(64, 97, 255);
1308 color_map[PIN_GROUP_LCD] = QColor(124, 255, 255);
1309 color_map[PIN_GROUP_SAIF] = QColor(255, 158, 158);
1310 color_map[PIN_GROUP_SSP] = QColor(222, 128, 255);
1311 color_map[PIN_GROUP_DUART] = QColor(192, 191, 191);
1312 color_map[PIN_GROUP_USB] = QColor(0, 255, 0);
1313 color_map[PIN_GROUP_NONE] = QColor(255, 255, 255);
1314
1315 for(int bank = 0; bank < 4; bank++)
1316 {
1317 QTableWidget *table = new QTableWidget;
1318 table->setColumnCount(7);
1319 table->setHorizontalHeaderItem(0, new QTableWidgetItem("Pin"));
1320 table->setHorizontalHeaderItem(1, new QTableWidgetItem("Function"));
1321 table->setHorizontalHeaderItem(2, new QTableWidgetItem("Direction"));
1322 table->setHorizontalHeaderItem(3, new QTableWidgetItem("Drive"));
1323 table->setHorizontalHeaderItem(4, new QTableWidgetItem("Voltage"));
1324 table->setHorizontalHeaderItem(5, new QTableWidgetItem("Pull"));
1325 table->setHorizontalHeaderItem(6, new QTableWidgetItem("Value"));
1326 table->verticalHeader()->setVisible(false);
1327 table->horizontalHeader()->setStretchLastSection(true);
1328 m_panel->addItem(table, QString("Bank %1").arg(bank));
1329 uint32_t muxsel[2], drive[4], pull, in, out, oe;
1330 bool error = false;
1331 for(int i = 0; i < 2; i++)
1332 if(!ReadRegisterOld("PINCTRL", QString("MUXSELn[%1]").arg(bank * 2 + i), muxsel[i]))
1333 error = true;
1334 /* don't make an error for those since some do not exist */
1335 for(int i = 0; i < 4; i++)
1336 if(!ReadRegisterOld("PINCTRL", QString("DRIVEn[%1]").arg(bank * 4 + i), drive[i]))
1337 drive[i] = 0;
1338 if(error)
1339 continue;
1340 if(!ReadRegisterOld("PINCTRL", QString("PULLn[%1]").arg(bank), pull))
1341 pull = 0;
1342 if(!ReadRegisterOld("PINCTRL", QString("DINn[%1]").arg(bank), in))
1343 in = 0;
1344 if(!ReadRegisterOld("PINCTRL", QString("DOUTn[%1]").arg(bank), out))
1345 out = 0;
1346 if(!ReadRegisterOld("PINCTRL", QString("DOEn[%1]").arg(bank), oe))
1347 oe = 0;
1348
1349 for(int pin = 0; pin < 32; pin++)
1350 {
1351 /* skip all-reserved pins */
1352 bool all_dis = true;
1353 for(int fn = 0; fn < 4; fn++)
1354 if(map[bank].pins[pin].function[fn].name != NULL)
1355 all_dis = false;
1356 if(all_dis)
1357 continue;
1358 /* add line */
1359 int row = table->rowCount();
1360 table->setRowCount(row + 1);
1361 /* name */
1362 table->setItem(row, 0, new QTableWidgetItem(QString("B%1P%2")
1363 .arg(bank).arg(pin, 2, 10, QChar('0'))));
1364 table->item(row, 0)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
1365 /* function */
1366 int fn = (muxsel[pin / 16] >> ((pin % 16) * 2)) & 3;
1367 table->setItem(row, 1, new QTableWidgetItem(QString(map[bank].pins[pin].function[fn].name)));
1368 table->item(row, 1)->setBackground(QBrush(color_map[map[bank].pins[pin].function[fn].group]));
1369 table->item(row, 1)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
1370 /* direction */
1371 table->setItem(row, 2, new QTableWidgetItem(fn != 3 ? "" : (oe & (1 << pin)) ? "Output" : "Input"));
1372 table->item(row, 2)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
1373 /* drive */
1374 int drv = (drive[pin / 8] >> ((pin % 8) * 4)) & 3;
1375 const char *strength[4] = {"4 mA", "8 mA", "12 mA", "16 mA"};
1376 table->setItem(row, 3, new QTableWidgetItem(QString(strength[drv])));
1377 table->item(row, 3)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
1378 /* voltage */
1379 int volt = (drive[pin / 8] >> (((pin % 8) * 4) + 2)) & 1;
1380 if(m_io_backend->GetSocName() == "imx233")
1381 volt = 1; /* cannot change voltage on imx233 */
1382 const char *voltage[2] = {"1.8 V", "3.3 V"};
1383 table->setItem(row, 4, new QTableWidgetItem(QString(voltage[volt])));
1384 table->item(row, 4)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
1385 /* pull */
1386 table->setItem(row, 5, new QTableWidgetItem(QString("%1").arg((pull >> pin) & 1)));
1387 table->item(row, 5)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
1388 /* input */
1389 table->setItem(row, 6, new QTableWidgetItem(QString("%1").arg((in >> pin) & 1)));
1390 table->item(row, 6)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
1391 }
1392 }
1393}
1394
1395static TmplAnalyserFactory< PinAnalyser > g_pin_factory(true, "Pin Analyser");