|
5 | 5 |
|
6 | 6 | #include <linux/acpi.h> |
7 | 7 | #include <linux/clk.h> |
| 8 | +#include <linux/cleanup.h> |
8 | 9 | #include <linux/delay.h> |
9 | 10 | #include <linux/devfreq.h> |
10 | 11 | #include <linux/gpio/consumer.h> |
@@ -102,6 +103,24 @@ static const struct __ufs_qcom_bw_table { |
102 | 103 | [MODE_MAX][0][0] = { 7643136, 819200 }, |
103 | 104 | }; |
104 | 105 |
|
| 106 | +static const struct { |
| 107 | + int nminor; |
| 108 | + char *prefix; |
| 109 | +} testbus_info[TSTBUS_MAX] = { |
| 110 | + [TSTBUS_UAWM] = {32, "TSTBUS_UAWM"}, |
| 111 | + [TSTBUS_UARM] = {32, "TSTBUS_UARM"}, |
| 112 | + [TSTBUS_TXUC] = {32, "TSTBUS_TXUC"}, |
| 113 | + [TSTBUS_RXUC] = {32, "TSTBUS_RXUC"}, |
| 114 | + [TSTBUS_DFC] = {32, "TSTBUS_DFC"}, |
| 115 | + [TSTBUS_TRLUT] = {32, "TSTBUS_TRLUT"}, |
| 116 | + [TSTBUS_TMRLUT] = {32, "TSTBUS_TMRLUT"}, |
| 117 | + [TSTBUS_OCSC] = {32, "TSTBUS_OCSC"}, |
| 118 | + [TSTBUS_UTP_HCI] = {32, "TSTBUS_UTP_HCI"}, |
| 119 | + [TSTBUS_COMBINED] = {32, "TSTBUS_COMBINED"}, |
| 120 | + [TSTBUS_WRAPPER] = {32, "TSTBUS_WRAPPER"}, |
| 121 | + [TSTBUS_UNIPRO] = {256, "TSTBUS_UNIPRO"}, |
| 122 | +}; |
| 123 | + |
105 | 124 | static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host); |
106 | 125 | static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, unsigned long freq); |
107 | 126 |
|
@@ -1644,13 +1663,101 @@ int ufs_qcom_testbus_config(struct ufs_qcom_host *host) |
1644 | 1663 | return 0; |
1645 | 1664 | } |
1646 | 1665 |
|
| 1666 | +static void ufs_qcom_dump_testbus(struct ufs_hba *hba) |
| 1667 | +{ |
| 1668 | + struct ufs_qcom_host *host = ufshcd_get_variant(hba); |
| 1669 | + int i, j, nminor = 0, testbus_len = 0; |
| 1670 | + u32 *testbus __free(kfree) = NULL; |
| 1671 | + char *prefix; |
| 1672 | + |
| 1673 | + testbus = kmalloc_array(256, sizeof(u32), GFP_KERNEL); |
| 1674 | + if (!testbus) |
| 1675 | + return; |
| 1676 | + |
| 1677 | + for (j = 0; j < TSTBUS_MAX; j++) { |
| 1678 | + nminor = testbus_info[j].nminor; |
| 1679 | + prefix = testbus_info[j].prefix; |
| 1680 | + host->testbus.select_major = j; |
| 1681 | + testbus_len = nminor * sizeof(u32); |
| 1682 | + for (i = 0; i < nminor; i++) { |
| 1683 | + host->testbus.select_minor = i; |
| 1684 | + ufs_qcom_testbus_config(host); |
| 1685 | + testbus[i] = ufshcd_readl(hba, UFS_TEST_BUS); |
| 1686 | + } |
| 1687 | + print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, |
| 1688 | + 16, 4, testbus, testbus_len, false); |
| 1689 | + } |
| 1690 | +} |
| 1691 | + |
| 1692 | +static int ufs_qcom_dump_regs(struct ufs_hba *hba, size_t offset, size_t len, |
| 1693 | + const char *prefix, enum ufshcd_res id) |
| 1694 | +{ |
| 1695 | + u32 *regs __free(kfree) = NULL; |
| 1696 | + size_t pos; |
| 1697 | + |
| 1698 | + if (offset % 4 != 0 || len % 4 != 0) |
| 1699 | + return -EINVAL; |
| 1700 | + |
| 1701 | + regs = kzalloc(len, GFP_ATOMIC); |
| 1702 | + if (!regs) |
| 1703 | + return -ENOMEM; |
| 1704 | + |
| 1705 | + for (pos = 0; pos < len; pos += 4) |
| 1706 | + regs[pos / 4] = readl(hba->res[id].base + offset + pos); |
| 1707 | + |
| 1708 | + print_hex_dump(KERN_ERR, prefix, |
| 1709 | + len > 4 ? DUMP_PREFIX_OFFSET : DUMP_PREFIX_NONE, |
| 1710 | + 16, 4, regs, len, false); |
| 1711 | + |
| 1712 | + return 0; |
| 1713 | +} |
| 1714 | + |
| 1715 | +static void ufs_qcom_dump_mcq_hci_regs(struct ufs_hba *hba) |
| 1716 | +{ |
| 1717 | + struct dump_info { |
| 1718 | + size_t offset; |
| 1719 | + size_t len; |
| 1720 | + const char *prefix; |
| 1721 | + enum ufshcd_res id; |
| 1722 | + }; |
| 1723 | + |
| 1724 | + struct dump_info mcq_dumps[] = { |
| 1725 | + {0x0, 256 * 4, "MCQ HCI-0 ", RES_MCQ}, |
| 1726 | + {0x400, 256 * 4, "MCQ HCI-1 ", RES_MCQ}, |
| 1727 | + {0x0, 5 * 4, "MCQ VS-0 ", RES_MCQ_VS}, |
| 1728 | + {0x0, 256 * 4, "MCQ SQD-0 ", RES_MCQ_SQD}, |
| 1729 | + {0x400, 256 * 4, "MCQ SQD-1 ", RES_MCQ_SQD}, |
| 1730 | + {0x800, 256 * 4, "MCQ SQD-2 ", RES_MCQ_SQD}, |
| 1731 | + {0xc00, 256 * 4, "MCQ SQD-3 ", RES_MCQ_SQD}, |
| 1732 | + {0x1000, 256 * 4, "MCQ SQD-4 ", RES_MCQ_SQD}, |
| 1733 | + {0x1400, 256 * 4, "MCQ SQD-5 ", RES_MCQ_SQD}, |
| 1734 | + {0x1800, 256 * 4, "MCQ SQD-6 ", RES_MCQ_SQD}, |
| 1735 | + {0x1c00, 256 * 4, "MCQ SQD-7 ", RES_MCQ_SQD}, |
| 1736 | + }; |
| 1737 | + |
| 1738 | + for (int i = 0; i < ARRAY_SIZE(mcq_dumps); i++) { |
| 1739 | + ufs_qcom_dump_regs(hba, mcq_dumps[i].offset, mcq_dumps[i].len, |
| 1740 | + mcq_dumps[i].prefix, mcq_dumps[i].id); |
| 1741 | + cond_resched(); |
| 1742 | + } |
| 1743 | +} |
| 1744 | + |
1647 | 1745 | static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba) |
1648 | 1746 | { |
1649 | 1747 | u32 reg; |
1650 | 1748 | struct ufs_qcom_host *host; |
1651 | 1749 |
|
1652 | 1750 | host = ufshcd_get_variant(hba); |
1653 | 1751 |
|
| 1752 | + dev_err(hba->dev, "HW_H8_ENTER_CNT=%d\n", ufshcd_readl(hba, REG_UFS_HW_H8_ENTER_CNT)); |
| 1753 | + dev_err(hba->dev, "HW_H8_EXIT_CNT=%d\n", ufshcd_readl(hba, REG_UFS_HW_H8_EXIT_CNT)); |
| 1754 | + |
| 1755 | + dev_err(hba->dev, "SW_H8_ENTER_CNT=%d\n", ufshcd_readl(hba, REG_UFS_SW_H8_ENTER_CNT)); |
| 1756 | + dev_err(hba->dev, "SW_H8_EXIT_CNT=%d\n", ufshcd_readl(hba, REG_UFS_SW_H8_EXIT_CNT)); |
| 1757 | + |
| 1758 | + dev_err(hba->dev, "SW_AFTER_HW_H8_ENTER_CNT=%d\n", |
| 1759 | + ufshcd_readl(hba, REG_UFS_SW_AFTER_HW_H8_ENTER_CNT)); |
| 1760 | + |
1654 | 1761 | ufshcd_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16 * 4, |
1655 | 1762 | "HCI Vendor Specific Registers "); |
1656 | 1763 |
|
@@ -1693,6 +1800,23 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba) |
1693 | 1800 |
|
1694 | 1801 | reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_TMRLUT); |
1695 | 1802 | ufshcd_dump_regs(hba, reg, 9 * 4, "UFS_DBG_RD_REG_TMRLUT "); |
| 1803 | + |
| 1804 | + if (hba->mcq_enabled) { |
| 1805 | + reg = ufs_qcom_get_debug_reg_offset(host, UFS_RD_REG_MCQ); |
| 1806 | + ufshcd_dump_regs(hba, reg, 64 * 4, "HCI MCQ Debug Registers "); |
| 1807 | + } |
| 1808 | + |
| 1809 | + /* ensure below dumps occur only in task context due to blocking calls. */ |
| 1810 | + if (in_task()) { |
| 1811 | + /* Dump MCQ Host Vendor Specific Registers */ |
| 1812 | + if (hba->mcq_enabled) |
| 1813 | + ufs_qcom_dump_mcq_hci_regs(hba); |
| 1814 | + |
| 1815 | + /* voluntarily yield the CPU as we are dumping too much data */ |
| 1816 | + ufshcd_dump_regs(hba, UFS_TEST_BUS, 4, "UFS_TEST_BUS "); |
| 1817 | + cond_resched(); |
| 1818 | + ufs_qcom_dump_testbus(hba); |
| 1819 | + } |
1696 | 1820 | } |
1697 | 1821 |
|
1698 | 1822 | /** |
|
0 commit comments