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