/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2014 by Amaury Pouly * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "std_analysers.h" #include /** * AnalyserEx */ AnalyserEx::AnalyserEx(const soc_desc::soc_ref_t& soc, IoBackend *backend) :Analyser(soc, backend), m_helper(backend, soc) { } bool AnalyserEx::ReadRegister(const QString& path, soc_word_t& val) { return m_helper.ReadRegister(m_helper.ParsePath(path), val); } bool AnalyserEx::ReadRegisterOld(const QString& dev, const QString& reg, soc_word_t& val) { return ReadRegister(dev + "." + reg, val); } bool AnalyserEx::ReadField(const QString& path, const QString& field, soc_word_t& val) { return m_helper.ReadRegisterField(m_helper.ParsePath(path), field, val); } bool AnalyserEx::ReadFieldOld(const QString& dev, const QString& reg, const QString& field, soc_word_t& val) { return ReadField(dev + "." + reg, field, val); } /** * Clock analyser */ ClockAnalyser::ClockAnalyser(const soc_desc::soc_ref_t& soc, IoBackend *backend) :AnalyserEx(soc, backend) { m_group = new QGroupBox("Clock Analyser"); QVBoxLayout *layout = new QVBoxLayout; m_group->setLayout(layout); m_tree_widget = new QTreeWidget; layout->addWidget(m_tree_widget); m_tree_widget->setColumnCount(2); QStringList list; list << "Name" << "Frequency"; m_tree_widget->setHeaderLabels(list); FillTree(); } ClockAnalyser::~ClockAnalyser() { delete m_group; } QWidget *ClockAnalyser::GetWidget() { return m_group; } bool ClockAnalyser::SupportSoc(const QString& soc_name) { return soc_name == "imx233" || soc_name == "rk27xx" || soc_name == "atj213x" || soc_name == "jz4760b" || soc_name == "stmp3700"; } QString ClockAnalyser::GetFreq(unsigned freq) { if(freq >= 1000000) { if((freq % 1000000) == 0) return QString().sprintf("%d MHz", freq / 1000000); else return QString().sprintf("%.3f MHz", freq / 1000000.0); } if(freq >= 1000) { if((freq % 1000) == 0) return QString().sprintf("%d KHz", freq / 1000); else return QString().sprintf("%.3f KHz", freq / 1000.0); } return QString().sprintf("%d Hz", freq); } QTreeWidgetItem *ClockAnalyser::AddClock(QTreeWidgetItem *parent, const QString& name, int freq, int mul, int div) { if(freq == FROM_PARENT) { int64_t f = GetClockFreq(parent); f *= mul; f /= div; freq = f; } QTreeWidgetItem *item = new QTreeWidgetItem(parent, QStringList() << name << (freq == INVALID ? "" : freq == 0 ? "" : GetFreq(freq))); item->setData(1, Qt::UserRole, freq); if(freq == DISABLED || freq == INVALID || (parent && parent->isDisabled())) item->setDisabled(true); if(!parent) m_tree_widget->addTopLevelItem(item); return item; } int ClockAnalyser::GetClockFreq(QTreeWidgetItem *item) { return item->data(1, Qt::UserRole).toInt(); } void ClockAnalyser::FillTree() { m_tree_widget->clear(); if(m_soc.get()->name == "imx233") FillTreeIMX233(); if(m_soc.get()->name == "stmp3700") FillTreeIMX233(); else if(m_soc.get()->name == "rk27xx") FillTreeRK27XX(); else if(m_soc.get()->name == "atj213x") FillTreeATJ213X(); else if(m_soc.get()->name == "jz4760b") FillTreeJZ4760B(); m_tree_widget->expandAll(); m_tree_widget->resizeColumnToContents(0); } void ClockAnalyser::FillTreeJZ4760B() { AddClock(0, "RTCLK", 32768); // assume EXCLK is 12MHz, we have no way to knowing for sure but this is the // recommended value anyway QTreeWidgetItem *exclk = AddClock(0, "EXCLK", 12000000); // PLL0 soc_word_t pllm, plln, pllod, pllbypass; QTreeWidgetItem *pll0 = 0; if(ReadFieldOld("CPM", "PLLCTRL0", "FEED_DIV", pllm) && ReadFieldOld("CPM", "PLLCTRL0", "IN_DIV", plln) && ReadFieldOld("CPM", "PLLCTRL0", "OUT_DIV", pllod) && ReadFieldOld("CPM", "PLLCTRL0", "BYPASS", pllbypass)) { pll0 = AddClock(exclk, "PLL0", FROM_PARENT, pllbypass ? 1 : 2 * pllm, pllbypass ? 1 : plln * (1 << pllod)); } else pll0 = AddClock(exclk, "PLL0", INVALID); // PLL1 soc_word_t plldiv, src_sel; QTreeWidgetItem *pll1 = 0; if(ReadFieldOld("CPM", "PLLCTRL1", "FEED_DIV", pllm) && ReadFieldOld("CPM", "PLLCTRL1", "IN_DIV", plln) && ReadFieldOld("CPM", "PLLCTRL1", "OUT_DIV", pllod) && ReadFieldOld("CPM", "PLLCTRL1", "SRC_SEL", src_sel) && ReadFieldOld("CPM", "PLLCTRL1", "PLL0_DIV", plldiv)) { pll1 = AddClock(src_sel ? pll0 : exclk, "PLL1", FROM_PARENT, 2 * pllm, plln * (1 << pllod) * (src_sel ? plldiv : 1)); } else pll1 = AddClock(exclk, "PLL1", INVALID); // system clocks const int NR_SYSCLK = 6; const char *sysclk[NR_SYSCLK] = { "CCLK", "SCLK", "PCLK", "HCLK", "H2CLK", "MCLK"}; for(int i = 0; i < NR_SYSCLK; i++) { soc_word_t div = 0; std::string field = std::string(sysclk[i]) + "_DIV"; if(ReadFieldOld("CPM", "SYSCLK", field.c_str(), div)) { switch(div) { case 0: div = 1; break; case 1: div = 2; break; case 2: div = 3; break; case 3: div = 4; break; case 4: div = 6; break; case 5: div = 8; break; default: div = 0; break; } } if(div != 0) AddClock(pll0, sysclk[i], FROM_PARENT, 1, div); else AddClock(pll0, sysclk[i], INVALID); } // common to msc, i2s, lcd, uhc, otg, ssi, pcm, gpu, gps soc_word_t pll_div; if(ReadFieldOld("CPM", "SYSCLK", "PLL_DIV", pll_div)) pll_div = pll_div ? 1 : 2; else pll_div = 1; // error // lcd soc_word_t pll_sel, div; if(ReadFieldOld("CPM", "LCDCLK", "DIV", div) && ReadFieldOld("CPM", "LCDCLK", "PLL_SEL", pll_sel)) { AddClock(pll_sel ? pll1 : pll0, "LCDCLK", FROM_PARENT, 1, pll_div * (div + 1)); } else AddClock(exclk, "LCDCLK", INVALID); } void ClockAnalyser::FillTreeATJ213X() { soc_word_t pllbypass, pllclk, en, coreclks, tmp0, tmp1, tmp2, tmp3; // system oscillators 32.768k and 24M QTreeWidgetItem *losc_clk = AddClock(0, "losc clk", 32768); QTreeWidgetItem *hosc_clk = AddClock(0, "hosc clk", 24000000); // core pll QTreeWidgetItem *corepll = 0; if(ReadFieldOld("CMU", "COREPLL", "CPEN", en) && ReadFieldOld("CMU", "COREPLL", "CPBY", pllbypass) && ReadFieldOld("CMU", "COREPLL", "CPCK", pllclk)) { corepll = AddClock(hosc_clk, "core pll", en ? FROM_PARENT : DISABLED, pllbypass ? 1 : pllclk, pllbypass ? 1 : 4); } else { corepll = AddClock(hosc_clk, "core pll", INVALID); } // dsp pll QTreeWidgetItem *dsppll = 0; if(ReadFieldOld("CMU", "DSPPLL", "DPEN", en) && ReadFieldOld("CMU", "DSPPLL", "DPCK", pllclk)) { dsppll = AddClock(hosc_clk, "dsp pll", en ? FROM_PARENT : DISABLED, pllbypass ? 1 : pllclk, pllbypass ? 1 : 4); } else { dsppll = AddClock(hosc_clk, "dsp pll", INVALID); } // audio pll QTreeWidgetItem *adcpll = 0; QTreeWidgetItem *dacpll = 0; if(ReadFieldOld("CMU", "AUDIOPLL", "APEN", en) && ReadFieldOld("CMU", "AUDIOPLL", "ADCCLK", tmp0) && ReadFieldOld("CMU", "AUDIOPLL", "DACCLK", tmp1)) { if(en) { adcpll = AddClock(hosc_clk, "audio adc pll", tmp0 ? 22579200 : 24576000); dacpll = AddClock(hosc_clk, "audio dac pll", tmp1 ? 22579200 : 24576000); } else { adcpll = AddClock(hosc_clk, "audio adc pll", DISABLED); dacpll = AddClock(hosc_clk, "audio dac pll", DISABLED); } } else { adcpll = AddClock(hosc_clk, "audio adc pll", INVALID); dacpll = AddClock(hosc_clk, "audio dac pll", INVALID); } // audio clocks QTreeWidgetItem *adcclk = 0; QTreeWidgetItem *dacclk = 0; if(ReadFieldOld("CMU", "AUDIOPLL", "ADCCLK", tmp0) && ReadFieldOld("CMU", "AUDIOPLL", "DACCLK", tmp1)) { adcclk = AddClock(adcpll, "audio adc clk", FROM_PARENT, 1, tmp0+1); dacclk = AddClock(dacpll, "audio dac clk", FROM_PARENT, 1, tmp1+1); } else { adcclk = AddClock(adcpll, "audio adc clk", INVALID); dacclk = AddClock(adcpll, "audio dac clk", INVALID); } // cpu clock QTreeWidgetItem *cpuclk = 0; if(ReadFieldOld("CMU", "BUSCLK", "CORECLKS", coreclks) && ReadFieldOld("CMU", "BUSCLK", "CCLKDIV", tmp0)) { if(coreclks == 0) cpuclk = AddClock(losc_clk, "cpu clk", FROM_PARENT, 1, tmp0+1); else if(coreclks == 1) cpuclk = AddClock(hosc_clk, "cpu clk", FROM_PARENT, 1, tmp0+1); else if(coreclks == 2) cpuclk = AddClock(corepll, "cpu clk", FROM_PARENT, 1, tmp0+1); else cpuclk = AddClock(corepll, "cpu clk", INVALID); } else { cpuclk = AddClock(corepll, "cpu clk", INVALID); } // system clock QTreeWidgetItem *sysclk = 0; if(ReadFieldOld("CMU", "BUSCLK", "SCLKDIV", tmp0)) sysclk = AddClock(cpuclk, "system clk", FROM_PARENT, 1, tmp0+1); else sysclk = AddClock(cpuclk, "system clk", INVALID); // peripherial clk QTreeWidgetItem *pclk = 0; if(ReadFieldOld("CMU", "BUSCLK", "PCLKDIV", tmp0)) pclk = AddClock(sysclk, "peripherial clk", FROM_PARENT, 1, tmp0 ? tmp0+1 : 2); else pclk = AddClock(sysclk, "peripherial clk", INVALID); // sdram clk QTreeWidgetItem *sdrclk = 0; if(ReadFieldOld("CMU", "DEVCLKEN", "SDRC", en) && ReadFieldOld("CMU", "DEVCLKEN", "SDRM", tmp0) && ReadFieldOld("SDR", "EN", "EN", tmp1) && ReadFieldOld("CMU", "SDRCLK", "SDRDIV", tmp2)) { en &= tmp0 & tmp1; sdrclk = AddClock(sysclk, "sdram clk", en ? FROM_PARENT: DISABLED, 1, tmp2+1); } else sdrclk = AddClock(sysclk, "sdram clk", INVALID); // nand clk QTreeWidgetItem *nandclk = 0; if(ReadFieldOld("CMU", "DEVCLKEN", "NAND", en) && ReadFieldOld("CMU", "NANDCLK", "NANDDIV", tmp0)) nandclk = AddClock(corepll, "nand clk", en ? FROM_PARENT : DISABLED, 1, tmp0+1); else nandclk = AddClock(corepll, "nand clk", INVALID); // sd clk QTreeWidgetItem *sdclk = 0; if(ReadFieldOld("CMU", "DEVCLKEN", "SD", tmp0) && ReadFieldOld("CMU", "SDCLK", "CKEN" , tmp1) && ReadFieldOld("CMU", "SDCLK", "D128" , tmp2) && ReadFieldOld("CMU", "SDCLK", "SDDIV" , tmp3)) { en = tmp0 & tmp1; sdclk = AddClock(corepll, "sd clk", en ? FROM_PARENT : DISABLED, 1, tmp2 ? 128*(tmp3+1) : (tmp3)); } else sdclk = AddClock(corepll, "sd clk", INVALID); // mha clk QTreeWidgetItem *mhaclk = 0; if(ReadFieldOld("CMU", "DEVCLKEN", "MHA", en) && ReadFieldOld("CMU", "MHACLK", "MHADIV", tmp1)) mhaclk = AddClock(corepll, "mha clk", en ? FROM_PARENT : DISABLED, 1, tmp1+1); else mhaclk = AddClock(corepll, "mha clk", INVALID); // mca clk QTreeWidgetItem *mcaclk = 0; if(ReadFieldOld("CMU", "DEVCLKEN", "MCA", en) && ReadFieldOld("CMU", "MCACLK", "MCADIV", tmp1)) mcaclk = AddClock(corepll, "mca clk", en ? FROM_PARENT : DISABLED, 1, tmp1+1); else mcaclk = AddClock(corepll, "mca clk", INVALID); // backlight pwm QTreeWidgetItem *pwmclk = 0; if(ReadFieldOld("CMU", "FMCLK", "BCKE", en) && ReadFieldOld("CMU", "FMCLK", "BCKS", tmp1) && ReadFieldOld("CMU", "FMCLK", "BCKCON", tmp2)) { if(tmp1) { // HOSC/8 input clk pwmclk = AddClock(hosc_clk, "pwm clk", en ? FROM_PARENT : DISABLED, 1, 3*(tmp2+1)); } else { // LOSC input clk pwmclk = AddClock(losc_clk, "pwm clk", en ? FROM_PARENT : DISABLED, 1, tmp2+1); } } else pwmclk = AddClock(losc_clk, "pwm clk", INVALID); // i2c clk QTreeWidgetItem *i2c1clk = 0; QTreeWidgetItem *i2c2clk = 0; if(ReadFieldOld("CMU", "DEVCLKEN", "I2C", en) && ReadFieldOld("I2C1", "CTL", "EN", tmp0) && ReadFieldOld("I2C1", "CLKDIV", "CLKDIV", tmp1)) { en &= tmp0; i2c1clk = AddClock(pclk, "i2c1 clk", en ? FROM_PARENT : DISABLED, 1, 16*(tmp1+1)); } else { i2c1clk = AddClock(pclk, "i2c1 clk", INVALID); } if(ReadFieldOld("CMU", "DEVCLKEN", "I2C", en) && ReadFieldOld("I2C2", "CTL", "EN", tmp0) && ReadFieldOld("I2C2", "CLKDIV", "CLKDIV", tmp1)) { en &= tmp0; i2c2clk = AddClock(pclk, "i2c2 clk", en ? FROM_PARENT : DISABLED, 1, 16*(tmp1+1)); } else { i2c2clk = AddClock(pclk, "i2c2 clk", INVALID); } Q_UNUSED(dsppll); Q_UNUSED(adcclk); Q_UNUSED(dacclk); Q_UNUSED(sdrclk); Q_UNUSED(nandclk); Q_UNUSED(sdclk); Q_UNUSED(mhaclk); Q_UNUSED(mcaclk); Q_UNUSED(pwmclk); Q_UNUSED(i2c1clk); Q_UNUSED(i2c2clk); } void ClockAnalyser::FillTreeRK27XX() { soc_word_t value, value2, value3, value4; soc_word_t bypass, clkr, clkf, clkod, pll_off; QTreeWidgetItem *xtal_clk = AddClock(0, "xtal clk", 24000000); // F = (Fref*F)/R/OD = (Fref*F)/R/OD QTreeWidgetItem *arm_pll = 0; if(ReadFieldOld("SCU", "PLLCON1", "ARM_PLL_BYPASS", bypass) && ReadFieldOld("SCU", "PLLCON1", "ARM_PLL_CLKR", clkr) && ReadFieldOld("SCU", "PLLCON1", "ARM_PLL_CLKF", clkf) && ReadFieldOld("SCU", "PLLCON1", "ARM_PLL_CLKOD", clkod) && ReadFieldOld("SCU", "PLLCON1", "ARM_PLL_POWERDOWN", pll_off)) { arm_pll = AddClock(xtal_clk, "arm pll", pll_off ? DISABLED : FROM_PARENT, bypass ? 1 : clkf+1, bypass ? 1 : (clkr+1)*(clkod+1)); } else { arm_pll = AddClock(xtal_clk, "arm pll", INVALID); } QTreeWidgetItem *arm_clk = 0; QTreeWidgetItem *hclk = 0; QTreeWidgetItem *pclk = 0; if(ReadFieldOld("SCU", "DIVCON1", "ARM_SLOW_MODE", value) && ReadFieldOld("SCU", "DIVCON1", "ARM_CLK_DIV", value2) && ReadFieldOld("SCU", "DIVCON1", "PCLK_CLK_DIV", value3)) { arm_clk = AddClock(value ? xtal_clk : arm_pll, "arm clk", FROM_PARENT, 1, value2 ? 2 : 1); hclk = AddClock(arm_clk, "hclk", FROM_PARENT, 1, value2 ? 1 : 2); pclk = AddClock(hclk, "pclk", FROM_PARENT, 1, (1< g_clock_factory(true, "Clock Analyser"); /** * EMI analyser */ EmiAnalyser::EmiAnalyser(const soc_desc::soc_ref_t& soc, IoBackend *backend) :AnalyserEx(soc, backend) { m_display_mode = DisplayCycles; m_group = new QGroupBox("EMI Analyser"); QVBoxLayout *layout = new QVBoxLayout; m_group->setLayout(layout); m_panel = new QToolBox; m_display_selector = new QComboBox; m_display_selector->addItem("Cycles", DisplayCycles); m_display_selector->addItem("Raw Hexadecimal", DisplayRawHex); m_display_selector->addItem("Time", DisplayTime); QHBoxLayout *line_layout = new QHBoxLayout; line_layout->addWidget(new QLabel("Display Mode:")); line_layout->addWidget(m_display_selector); m_emi_freq_label = new QLineEdit; m_emi_freq_label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); m_emi_freq_label->setReadOnly(true); m_emi_size_label = new QLineEdit; m_emi_size_label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); m_emi_size_label->setReadOnly(true); line_layout->addStretch(); line_layout->addWidget(new QLabel("Size:")); line_layout->addWidget(m_emi_size_label); line_layout->addWidget(new QLabel("MiB")); line_layout->addStretch(); line_layout->addWidget(new QLabel("Frequency:")); line_layout->addWidget(m_emi_freq_label); line_layout->addWidget(new QLabel("MHz")); line_layout->addStretch(); layout->addLayout(line_layout); layout->addWidget(m_panel); connect(m_display_selector, SIGNAL(currentIndexChanged(int)), this, SLOT(OnChangeDisplayMode(int))); FillTable(); } EmiAnalyser::~EmiAnalyser() { delete m_group; } QWidget *EmiAnalyser::GetWidget() { return m_group; } bool EmiAnalyser::SupportSoc(const QString& soc_name) { return soc_name == "imx233" || soc_name == "stmp3700"; } void EmiAnalyser::OnChangeDisplayMode(int index) { if(index == -1) return; m_display_mode = (DisplayMode)m_display_selector->itemData(index).toInt(); int idx = m_panel->currentIndex(); FillTable(); m_panel->setCurrentIndex(idx); } void EmiAnalyser::NewGroup(const QString& name) { QTableWidget *table = new QTableWidget; table->setColumnCount(3); table->setHorizontalHeaderItem(0, new QTableWidgetItem("Name")); table->setHorizontalHeaderItem(1, new QTableWidgetItem("Value")); table->setHorizontalHeaderItem(2, new QTableWidgetItem("Comment")); table->verticalHeader()->setVisible(false); table->horizontalHeader()->setStretchLastSection(true); m_panel->addItem(table, name); } void EmiAnalyser::AddLine(const QString& name, int value, const QString& unit, const QString& comment) { QTableWidget *table = dynamic_cast< QTableWidget* >(m_panel->widget(m_panel->count() - 1)); int row = table->rowCount(); table->setRowCount(row + 1); table->setItem(row, 0, new QTableWidgetItem(name)); QString val; if(value == INVALID) val = ""; else if(value == NONE) val = unit; else if(m_display_mode == DisplayRawHex && unit.size() == 0) val = QString("0x%1").arg(value, 0, 16); else val = QString("%1%2").arg(value).arg(unit); table->setItem(row, 1, new QTableWidgetItem(val)); table->item(row, 1)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); table->setItem(row, 2, new QTableWidgetItem(comment)); table->resizeColumnToContents(0); table->resizeColumnToContents(1); } void EmiAnalyser::AddCycleLine(const QString& name, unsigned raw_val, float val, int digits, const QString& comment) { if(m_display_mode == DisplayCycles) { QString str; if(digits == 0) str = QString("%1").arg((int)val); else str = QString("%1").arg(val, 0, 'f', digits); str += " cycles"; AddLine(name, NONE, str, comment); } else if(m_display_mode == DisplayRawHex) { QString str = QString("0x%1").arg(raw_val, 0, 16); AddLine(name, NONE, str, comment); } else if(m_display_mode == DisplayTime && m_emi_freq != 0) { float cycle_time_ns = 1000000000.0 / m_emi_freq; val *= cycle_time_ns; QString str; if(val >= 1000) str = QString::fromWCharArray(L"%1 µs").arg(val / 1000.0, 0, 'f', 2); else str = QString("%1 ns").arg(val, 0, 'f', 2); AddLine(name, NONE, str, comment); } else AddLine(name, raw_val, " cycles", comment); } void EmiAnalyser::FillTable() { while(m_panel->count() > 0) m_panel->removeItem(0); soc_word_t value; m_emi_freq = 0; if(ReadFieldOld("CLKCTRL", "CLKSEQ", "BYPASS_EMI", value)) { bool ret; if(value) { m_emi_freq = 24000000; ret = ReadFieldOld("CLKCTRL", "EMI", "DIV_XTAL", value); } else { m_emi_freq = 480000000; if(ReadFieldOld("CLKCTRL", "FRAC", "EMIFRAC", value)) m_emi_freq = 18 * (int64_t)m_emi_freq / value; else m_emi_freq = 0; ret = ReadFieldOld("CLKCTRL", "EMI", "DIV_EMI", value); } if(ret) m_emi_freq /= value; else m_emi_freq = 0; } m_emi_freq_label->setText(QString().sprintf("%.3f", m_emi_freq / 1000000.0)); soc_word_t rows, columns, cs_map; if(ReadFieldOld("DRAM", "CTL14", "CS_MAP", cs_map) && ReadFieldOld("DRAM", "CTL10", "ADDR_PINS", rows) && ReadFieldOld("DRAM", "CTL11", "COLUMN_SIZE", columns)) { rows = 13 - rows; columns = 12 - columns; soc_word_t banks = 4; soc_word_t chips = __builtin_popcount(cs_map); unsigned long size = 2 * (1 << (rows + columns)) * chips * banks; m_emi_size_label->setText(QString().sprintf("%lu", (unsigned long)size / 1024 / 1024)); } else m_emi_size_label->setText(""); NewGroup("Control Parameters"); if(ReadFieldOld("EMI", "CTRL", "PORT_PRIORITY_ORDER", value)) { QStringList ports; ports << "AXI0" << "AHB1" << "AHB2" << "AHB3"; QString order; order += ports[value / 6]; ports.erase(ports.begin() + value / 6); int ord[6][3] = { {0, 1, 2}, {2, 0, 1}, {1, 2, 0}, {2, 1, 0}, {1, 0, 2}, {0, 2, 1} }; for(int i = 0; i < 3; i++) order += ", " + ports[ord[value % 6][i]]; AddLine("Port Priority Order", value, "", order); } if(ReadFieldOld("EMI", "CTRL", "MEM_WIDTH", value)) AddLine("Memory Width", value ? 16 : 8, "-bit"); if(ReadFieldOld("DRAM", "CTL03", "AP", value)) AddLine("Auto Pre-Charge", NONE, value ? "Yes" : "No"); bool bypass_mode = false; if(ReadFieldOld("DRAM", "CTL04", "DLL_BYPASS_MODE", value)) { bypass_mode = value == 1; AddLine("DLL Bypass Mode", NONE, value ? "Yes" : "No"); } if(ReadFieldOld("DRAM", "CTL05", "EN_LOWPOWER_MODE", value)) AddLine("Low Power Mode", NONE, value ? "Enabled" : "Disabled"); if(ReadFieldOld("DRAM", "CTL08", "SREFRESH", value)) AddLine("Self Refresh", NONE, value ? "Yes" : "No"); if(ReadFieldOld("DRAM", "CTL08", "SDR_MODE", value)) AddLine("Mode", NONE, value ? "SDR" : "DDR"); if(ReadFieldOld("DRAM", "CTL10", "ADDR_PINS", value)) AddLine("Address Pins", 13 - value, ""); if(ReadFieldOld("DRAM", "CTL11", "COLUMN_SIZE", value)) AddLine("Column Size", 12 - value, "-bit"); if(ReadFieldOld("DRAM", "CTL11", "CASLAT", value)) AddLine("Encoded CAS", value, "", "Memory device dependent"); if(ReadFieldOld("DRAM", "CTL14", "CS_MAP", value)) { QString v; for(int i = 0; i < 4; i++) if(value & (1 << i)) { if(v.size() != 0) v += " "; v += QString("%1").arg(i); } AddLine("Chip Select Pins", NONE, v, ""); } if(ReadFieldOld("DRAM", "CTL37", "TREF_ENABLE", value)) AddLine("Refresh Commands", NONE, value ? "Enabled" : "Disabled", "Issue self-refresh every TREF cycles"); NewGroup("Frequency Parameters"); if(ReadFieldOld("DRAM", "CTL13", "CASLAT_LIN_GATE", value)) { if(value >= 3 && value <= 10 && value != 9) { float v = (value / 2) + 0.5 * (value % 2); AddCycleLine("CAS Gate", value, v, 1, ""); } else AddLine("CAS Gate", NONE, "Reserved", "Reserved value"); } if(ReadFieldOld("DRAM", "CTL13", "CASLAT_LIN", value)) { if(value >= 3 && value <= 10 && value != 9) { float v = (value / 2) + 0.5 * (value % 2); AddCycleLine("CAS Latency", value, v, 1, ""); } else AddLine("CAS Latency", NONE, "Reserved", "Reserved value"); } if(ReadFieldOld("DRAM", "CTL12", "TCKE", value)) AddCycleLine("tCKE", value, value, 0, "Minimum CKE pulse width"); if(ReadFieldOld("DRAM", "CTL15", "TDAL", value)) AddCycleLine("tDAL", value, value, 0, "Auto pre-charge write recovery time"); if(ReadFieldOld("DRAM", "CTL31", "TDLL", value)) AddCycleLine("tDLL", value, value, 0, "DLL lock time"); if(ReadFieldOld("DRAM", "CTL10", "TEMRS", value)) AddCycleLine("tEMRS", value, value, 0, "Extended mode parameter set time"); if(ReadFieldOld("DRAM", "CTL34", "TINIT", value)) AddCycleLine("tINIT", value, value, 0, "Initialisation time"); if(ReadFieldOld("DRAM", "CTL16", "TMRD", value)) AddCycleLine("tMRD", value, value, 0, "Mode register set command time"); if(ReadFieldOld("DRAM", "CTL40", "TPDEX", value)) AddCycleLine("tPDEX", value, value, 0, "Power down exit time"); if(ReadFieldOld("DRAM", "CTL32", "TRAS_MAX", value)) AddCycleLine("tRAS Max", value, value, 0, "Maximum row activate time"); if(ReadFieldOld("DRAM", "CTL20", "TRAS_MIN", value)) AddCycleLine("tRAS Min", value, value, 0, "Minimum row activate time"); if(ReadFieldOld("DRAM", "CTL17", "TRC", value)) AddCycleLine("tRC", value, value, 0, "Activate to activate delay (same bank)"); if(ReadFieldOld("DRAM", "CTL20", "TRCD_INT", value)) AddCycleLine("tRCD", value, value, 0, "RAS to CAS"); if(ReadFieldOld("DRAM", "CTL26", "TREF", value)) AddCycleLine("tREF", value, value, 0, "Refresh to refresh time"); if(ReadFieldOld("DRAM", "CTL21", "TRFC", value)) AddCycleLine("tRFC", value, value, 0, "Refresh command time"); if(ReadFieldOld("DRAM", "CTL15", "TRP", value)) AddCycleLine("tRP", value, value, 0, "Pre-charge command time"); if(ReadFieldOld("DRAM", "CTL12", "TRRD", value)) AddCycleLine("tRRD", value, value, 0, "Activate to activate delay (different banks)"); if(ReadFieldOld("DRAM", "CTL12", "TWR_INT", value)) AddCycleLine("tWR", value, value, 0, "Write recovery time"); if(ReadFieldOld("DRAM", "CTL13", "TWTR", value)) AddCycleLine("tWTR", value, value, 0, "Write to read delay"); if(ReadFieldOld("DRAM", "CTL32", "TXSNR", value)) AddCycleLine("tXSNR", value, value, 0, ""); if(ReadFieldOld("DRAM", "CTL33", "TXSR", value)) AddCycleLine("tXSR", value, value, 0, "Self-refresh exit time"); NewGroup("DLL Parameters"); if(bypass_mode) { if(ReadFieldOld("DRAM", "CTL19", "DLL_DQS_DELAY_BYPASS_0", value)) AddLine("DLL DQS Delay 0", value, "", "In 1/128 fraction of a cycle (bypass mode)"); if(ReadFieldOld("DRAM", "CTL19", "DLL_DQS_DELAY_BYPASS_0", value)) AddLine("DLL DQS Delay 1", value, "", "In 1/128 fraction of a cycle (bypass mode)"); if(ReadFieldOld("DRAM", "CTL19", "DQS_OUT_SHIFT_BYPASS", value)) AddLine("DQS Out Delay", value, "", "(bypass mode)"); if(ReadFieldOld("DRAM", "CTL20", "WR_DQS_SHIFT_BYPASS", value)) AddLine("DQS Write Delay", value, "", "(bypass mode)"); } else { if(ReadFieldOld("DRAM", "CTL17", "DLL_START_POINT", value)) AddLine("DLL Start Point", value, "", "Initial delay count"); if(ReadFieldOld("DRAM", "CTL17", "DLL_INCREMENT", value)) AddLine("DLL Increment", value, "", "Delay increment"); if(ReadFieldOld("DRAM", "CTL18", "DLL_DQS_DELAY_0", value)) AddLine("DLL DQS Delay 0", value, "", "In 1/128 fraction of a cycle"); if(ReadFieldOld("DRAM", "CTL18", "DLL_DQS_DELAY_1", value)) AddLine("DLL DQS Delay 1", value, "", "In 1/128 fraction of a cycle"); if(ReadFieldOld("DRAM", "CTL19", "DQS_OUT_SHIFT", value)) AddLine("DQS Out Delay", value, "", ""); if(ReadFieldOld("DRAM", "CTL20", "WR_DQS_SHIFT", value)) AddLine("DQS Write Delay", value, "", ""); } } static TmplAnalyserFactory< EmiAnalyser > g_emi_factory(true, "EMI Analyser"); /** * Pin analyser */ namespace pin_desc { #include "../../imxtools/misc/map.h" } PinAnalyser::PinAnalyser(const soc_desc::soc_ref_t& soc, IoBackend *backend) :AnalyserEx(soc, backend) { m_group = new QGroupBox("Pin Analyser"); QVBoxLayout *layout = new QVBoxLayout; m_group->setLayout(layout); QLabel *label = new QLabel("Package:"); m_package_edit = new QLineEdit; m_package_edit->setReadOnly(true); m_package_edit->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); QHBoxLayout *hlayout = new QHBoxLayout; hlayout->addStretch(); hlayout->addWidget(label); hlayout->addWidget(m_package_edit); hlayout->addStretch(); layout->addLayout(hlayout); m_panel = new QToolBox; layout->addWidget(m_panel); FillList(); } PinAnalyser::~PinAnalyser() { delete m_group; } QWidget *PinAnalyser::GetWidget() { return m_group; } bool PinAnalyser::SupportSoc(const QString& soc_name) { return soc_name == "imx233" || soc_name == "stmp3700"; } void PinAnalyser::FillList() { soc_word_t value; while(m_panel->count() > 0) m_panel->removeItem(0); const char *package_type[8] = { "bga169", "bga100", "lqfp100", "lqfp128", 0, 0, 0, 0 }; if(!ReadFieldOld("DIGCTL", "STATUS", "PACKAGE_TYPE", value)) { m_package_edit->setText(""); return; } if(value >= 8 || package_type[value] == NULL) { m_package_edit->setText(""); return; } const char *package = package_type[value]; m_package_edit->setText(package); pin_desc::bank_map_t *map = NULL; for(size_t i = 0; i < sizeof(pin_desc::socs) / sizeof(pin_desc::socs[0]); i++) if(QString(pin_desc::socs[i].soc) == m_io_backend->GetSocName() && QString(pin_desc::socs[i].ver) == package) map = pin_desc::socs[i].map; if(map == NULL) { m_package_edit->setText(QString("%1 (no map available)").arg(package)); return; } QMap< unsigned, QColor > color_map; color_map[PIN_GROUP_EMI] = QColor(255, 255, 64); color_map[PIN_GROUP_GPIO] = QColor(171, 214, 230); color_map[PIN_GROUP_I2C] = QColor(191, 191, 255); color_map[PIN_GROUP_JTAG] = QColor(238, 75, 21); color_map[PIN_GROUP_PWM] = QColor(255, 236, 179); color_map[PIN_GROUP_SPDIF] = QColor(174, 235, 63); color_map[PIN_GROUP_TIMROT] = QColor(255, 112, 237); color_map[PIN_GROUP_AUART] = QColor(94, 255, 128); color_map[PIN_GROUP_ETM] = QColor(168, 53, 14); color_map[PIN_GROUP_GPMI] = QColor(255, 211, 147); color_map[PIN_GROUP_IrDA] = QColor(64, 97, 255); color_map[PIN_GROUP_LCD] = QColor(124, 255, 255); color_map[PIN_GROUP_SAIF] = QColor(255, 158, 158); color_map[PIN_GROUP_SSP] = QColor(222, 128, 255); color_map[PIN_GROUP_DUART] = QColor(192, 191, 191); color_map[PIN_GROUP_USB] = QColor(0, 255, 0); color_map[PIN_GROUP_NONE] = QColor(255, 255, 255); for(int bank = 0; bank < 4; bank++) { QTableWidget *table = new QTableWidget; table->setColumnCount(7); table->setHorizontalHeaderItem(0, new QTableWidgetItem("Pin")); table->setHorizontalHeaderItem(1, new QTableWidgetItem("Function")); table->setHorizontalHeaderItem(2, new QTableWidgetItem("Direction")); table->setHorizontalHeaderItem(3, new QTableWidgetItem("Drive")); table->setHorizontalHeaderItem(4, new QTableWidgetItem("Voltage")); table->setHorizontalHeaderItem(5, new QTableWidgetItem("Pull")); table->setHorizontalHeaderItem(6, new QTableWidgetItem("Value")); table->verticalHeader()->setVisible(false); table->horizontalHeader()->setStretchLastSection(true); m_panel->addItem(table, QString("Bank %1").arg(bank)); uint32_t muxsel[2], drive[4], pull, in, out, oe; bool error = false; for(int i = 0; i < 2; i++) if(!ReadRegisterOld("PINCTRL", QString("MUXSELn[%1]").arg(bank * 2 + i), muxsel[i])) error = true; /* don't make an error for those since some do not exist */ for(int i = 0; i < 4; i++) if(!ReadRegisterOld("PINCTRL", QString("DRIVEn[%1]").arg(bank * 4 + i), drive[i])) drive[i] = 0; if(error) continue; if(!ReadRegisterOld("PINCTRL", QString("PULLn[%1]").arg(bank), pull)) pull = 0; if(!ReadRegisterOld("PINCTRL", QString("DINn[%1]").arg(bank), in)) in = 0; if(!ReadRegisterOld("PINCTRL", QString("DOUTn[%1]").arg(bank), out)) out = 0; if(!ReadRegisterOld("PINCTRL", QString("DOEn[%1]").arg(bank), oe)) oe = 0; for(int pin = 0; pin < 32; pin++) { /* skip all-reserved pins */ bool all_dis = true; for(int fn = 0; fn < 4; fn++) if(map[bank].pins[pin].function[fn].name != NULL) all_dis = false; if(all_dis) continue; /* add line */ int row = table->rowCount(); table->setRowCount(row + 1); /* name */ table->setItem(row, 0, new QTableWidgetItem(QString("B%1P%2") .arg(bank).arg(pin, 2, 10, QChar('0')))); table->item(row, 0)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); /* function */ int fn = (muxsel[pin / 16] >> ((pin % 16) * 2)) & 3; table->setItem(row, 1, new QTableWidgetItem(QString(map[bank].pins[pin].function[fn].name))); table->item(row, 1)->setBackground(QBrush(color_map[map[bank].pins[pin].function[fn].group])); table->item(row, 1)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); /* direction */ table->setItem(row, 2, new QTableWidgetItem(fn != 3 ? "" : (oe & (1 << pin)) ? "Output" : "Input")); table->item(row, 2)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); /* drive */ int drv = (drive[pin / 8] >> ((pin % 8) * 4)) & 3; const char *strength[4] = {"4 mA", "8 mA", "12 mA", "16 mA"}; table->setItem(row, 3, new QTableWidgetItem(QString(strength[drv]))); table->item(row, 3)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); /* voltage */ int volt = (drive[pin / 8] >> (((pin % 8) * 4) + 2)) & 1; if(m_io_backend->GetSocName() == "imx233") volt = 1; /* cannot change voltage on imx233 */ const char *voltage[2] = {"1.8 V", "3.3 V"}; table->setItem(row, 4, new QTableWidgetItem(QString(voltage[volt]))); table->item(row, 4)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); /* pull */ table->setItem(row, 5, new QTableWidgetItem(QString("%1").arg((pull >> pin) & 1))); table->item(row, 5)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); /* input */ table->setItem(row, 6, new QTableWidgetItem(QString("%1").arg((in >> pin) & 1))); table->item(row, 6)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); } } } static TmplAnalyserFactory< PinAnalyser > g_pin_factory(true, "Pin Analyser");