From 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Tue, 22 Oct 2024 10:36:11 +0000 Subject: [PATCH] 修改4g拨号为QMI,需要在系统里后台执行quectel-CM --- kernel/drivers/memory/tegra/mc.c | 192 +++++++++++++++++++++++++++-------------------- 1 files changed, 111 insertions(+), 81 deletions(-) diff --git a/kernel/drivers/memory/tegra/mc.c b/kernel/drivers/memory/tegra/mc.c index 346d8ea..ec84035 100644 --- a/kernel/drivers/memory/tegra/mc.c +++ b/kernel/drivers/memory/tegra/mc.c @@ -1,17 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/clk.h> #include <linux/delay.h> +#include <linux/dma-mapping.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/sort.h> @@ -20,38 +19,9 @@ #include "mc.h" -#define MC_INTSTATUS 0x000 - -#define MC_INTMASK 0x004 - -#define MC_ERR_STATUS 0x08 -#define MC_ERR_STATUS_TYPE_SHIFT 28 -#define MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE (6 << MC_ERR_STATUS_TYPE_SHIFT) -#define MC_ERR_STATUS_TYPE_MASK (0x7 << MC_ERR_STATUS_TYPE_SHIFT) -#define MC_ERR_STATUS_READABLE (1 << 27) -#define MC_ERR_STATUS_WRITABLE (1 << 26) -#define MC_ERR_STATUS_NONSECURE (1 << 25) -#define MC_ERR_STATUS_ADR_HI_SHIFT 20 -#define MC_ERR_STATUS_ADR_HI_MASK 0x3 -#define MC_ERR_STATUS_SECURITY (1 << 17) -#define MC_ERR_STATUS_RW (1 << 16) - -#define MC_ERR_ADR 0x0c - -#define MC_DECERR_EMEM_OTHERS_STATUS 0x58 -#define MC_SECURITY_VIOLATION_STATUS 0x74 - -#define MC_EMEM_ARB_CFG 0x90 -#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(x) (((x) & 0x1ff) << 0) -#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK 0x1ff -#define MC_EMEM_ARB_MISC0 0xd8 - -#define MC_EMEM_ADR_CFG 0x54 -#define MC_EMEM_ADR_CFG_EMEM_NUMDEV BIT(0) - static const struct of_device_id tegra_mc_of_match[] = { #ifdef CONFIG_ARCH_TEGRA_2x_SOC - { .compatible = "nvidia,tegra20-mc", .data = &tegra20_mc_soc }, + { .compatible = "nvidia,tegra20-mc-gart", .data = &tegra20_mc_soc }, #endif #ifdef CONFIG_ARCH_TEGRA_3x_SOC { .compatible = "nvidia,tegra30-mc", .data = &tegra30_mc_soc }, @@ -72,7 +42,7 @@ }; MODULE_DEVICE_TABLE(of, tegra_mc_of_match); -static int terga_mc_block_dma_common(struct tegra_mc *mc, +static int tegra_mc_block_dma_common(struct tegra_mc *mc, const struct tegra_mc_reset *rst) { unsigned long flags; @@ -88,13 +58,13 @@ return 0; } -static bool terga_mc_dma_idling_common(struct tegra_mc *mc, +static bool tegra_mc_dma_idling_common(struct tegra_mc *mc, const struct tegra_mc_reset *rst) { return (mc_readl(mc, rst->status) & BIT(rst->bit)) != 0; } -static int terga_mc_unblock_dma_common(struct tegra_mc *mc, +static int tegra_mc_unblock_dma_common(struct tegra_mc *mc, const struct tegra_mc_reset *rst) { unsigned long flags; @@ -110,17 +80,17 @@ return 0; } -static int terga_mc_reset_status_common(struct tegra_mc *mc, +static int tegra_mc_reset_status_common(struct tegra_mc *mc, const struct tegra_mc_reset *rst) { return (mc_readl(mc, rst->control) & BIT(rst->bit)) != 0; } -const struct tegra_mc_reset_ops terga_mc_reset_ops_common = { - .block_dma = terga_mc_block_dma_common, - .dma_idling = terga_mc_dma_idling_common, - .unblock_dma = terga_mc_unblock_dma_common, - .reset_status = terga_mc_reset_status_common, +const struct tegra_mc_reset_ops tegra_mc_reset_ops_common = { + .block_dma = tegra_mc_block_dma_common, + .dma_idling = tegra_mc_dma_idling_common, + .unblock_dma = tegra_mc_unblock_dma_common, + .reset_status = tegra_mc_reset_status_common, }; static inline struct tegra_mc *reset_to_mc(struct reset_controller_dev *rcdev) @@ -161,7 +131,7 @@ /* block clients DMA requests */ err = rst_ops->block_dma(mc, rst); if (err) { - dev_err(mc->dev, "Failed to block %s DMA: %d\n", + dev_err(mc->dev, "failed to block %s DMA: %d\n", rst->name, err); return err; } @@ -171,7 +141,7 @@ /* wait for completion of the outstanding DMA requests */ while (!rst_ops->dma_idling(mc, rst)) { if (!retries--) { - dev_err(mc->dev, "Failed to flush %s DMA\n", + dev_err(mc->dev, "failed to flush %s DMA\n", rst->name); return -EBUSY; } @@ -184,7 +154,7 @@ /* clear clients DMA requests sitting before arbitration */ err = rst_ops->hotreset_assert(mc, rst); if (err) { - dev_err(mc->dev, "Failed to hot reset %s: %d\n", + dev_err(mc->dev, "failed to hot reset %s: %d\n", rst->name, err); return err; } @@ -213,7 +183,7 @@ /* take out client from hot reset */ err = rst_ops->hotreset_deassert(mc, rst); if (err) { - dev_err(mc->dev, "Failed to deassert hot reset %s: %d\n", + dev_err(mc->dev, "failed to deassert hot reset %s: %d\n", rst->name, err); return err; } @@ -223,7 +193,7 @@ /* allow new DMA requests to proceed to arbitration */ err = rst_ops->unblock_dma(mc, rst); if (err) { - dev_err(mc->dev, "Failed to unblock %s DMA : %d\n", + dev_err(mc->dev, "failed to unblock %s DMA : %d\n", rst->name, err); return err; } @@ -283,26 +253,29 @@ tick = (unsigned long long)mc->tick * clk_get_rate(mc->clk); do_div(tick, NSEC_PER_SEC); - value = readl(mc->regs + MC_EMEM_ARB_CFG); + value = mc_readl(mc, MC_EMEM_ARB_CFG); value &= ~MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK; value |= MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(tick); - writel(value, mc->regs + MC_EMEM_ARB_CFG); + mc_writel(mc, value, MC_EMEM_ARB_CFG); /* write latency allowance defaults */ for (i = 0; i < mc->soc->num_clients; i++) { const struct tegra_mc_la *la = &mc->soc->clients[i].la; u32 value; - value = readl(mc->regs + la->reg); + value = mc_readl(mc, la->reg); value &= ~(la->mask << la->shift); value |= (la->def & la->mask) << la->shift; - writel(value, mc->regs + la->reg); + mc_writel(mc, value, la->reg); } + + /* latch new values */ + mc_writel(mc, MC_TIMING_UPDATE, MC_TIMING_CONTROL); return 0; } -void tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate) +int tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate) { unsigned int i; struct tegra_mc_timing *timing = NULL; @@ -317,11 +290,13 @@ if (!timing) { dev_err(mc->dev, "no memory timing registered for rate %lu\n", rate); - return; + return -EINVAL; } for (i = 0; i < mc->soc->num_emem_regs; ++i) mc_writel(mc, timing->emem_data[i], mc->soc->emem_regs[i]); + + return 0; } unsigned int tegra_mc_get_emem_device_count(struct tegra_mc *mc) @@ -345,7 +320,7 @@ err = of_property_read_u32(node, "clock-frequency", &tmp); if (err) { dev_err(mc->dev, - "timing %s: failed to read rate\n", node->name); + "timing %pOFn: failed to read rate\n", node); return err; } @@ -360,8 +335,8 @@ mc->soc->num_emem_regs); if (err) { dev_err(mc->dev, - "timing %s: failed to read EMEM configuration\n", - node->name); + "timing %pOFn: failed to read EMEM configuration\n", + node); return err; } @@ -575,8 +550,15 @@ break; case MC_INT_INVALID_GART_PAGE: - dev_err_ratelimited(mc->dev, "%s\n", error); - continue; + reg = MC_GART_ERROR_REQ; + value = mc_readl(mc, reg); + + id = (value >> 1) & mc->soc->client_id_mask; + desc = error_names[2]; + + if (value & BIT(0)) + direction = "write"; + break; case MC_INT_SECURITY_VIOLATION: reg = MC_SECURITY_VIOLATION_STATUS; @@ -611,15 +593,11 @@ static int tegra_mc_probe(struct platform_device *pdev) { - const struct of_device_id *match; struct resource *res; struct tegra_mc *mc; void *isr; + u64 mask; int err; - - match = of_match_node(tegra_mc_of_match, pdev->dev.of_node); - if (!match) - return -ENODEV; mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL); if (!mc) @@ -627,8 +605,16 @@ platform_set_drvdata(pdev, mc); spin_lock_init(&mc->lock); - mc->soc = match->data; + mc->soc = of_device_get_match_data(&pdev->dev); mc->dev = &pdev->dev; + + mask = DMA_BIT_MASK(mc->soc->num_address_bits); + + err = dma_coerce_mask_and_coherent(&pdev->dev, mask); + if (err < 0) { + dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err); + return err; + } /* length of MC tick in nanoseconds */ mc->tick = 30; @@ -638,27 +624,26 @@ if (IS_ERR(mc->regs)) return PTR_ERR(mc->regs); + mc->clk = devm_clk_get(&pdev->dev, "mc"); + if (IS_ERR(mc->clk)) { + dev_err(&pdev->dev, "failed to get MC clock: %ld\n", + PTR_ERR(mc->clk)); + return PTR_ERR(mc->clk); + } + #ifdef CONFIG_ARCH_TEGRA_2x_SOC if (mc->soc == &tegra20_mc_soc) { - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - mc->regs2 = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(mc->regs2)) - return PTR_ERR(mc->regs2); - isr = tegra20_mc_irq; } else #endif { - mc->clk = devm_clk_get(&pdev->dev, "mc"); - if (IS_ERR(mc->clk)) { - dev_err(&pdev->dev, "failed to get MC clock: %ld\n", - PTR_ERR(mc->clk)); - return PTR_ERR(mc->clk); - } + /* ensure that debug features are disabled */ + mc_writel(mc, 0x00000000, MC_TIMING_CONTROL_DBG); err = tegra_mc_setup_latency_allowance(mc); if (err < 0) { - dev_err(&pdev->dev, "failed to setup latency allowance: %d\n", + dev_err(&pdev->dev, + "failed to setup latency allowance: %d\n", err); return err; } @@ -679,11 +664,11 @@ return mc->irq; } - WARN(!mc->soc->client_id_mask, "Missing client ID mask for this SoC\n"); + WARN(!mc->soc->client_id_mask, "missing client ID mask for this SoC\n"); mc_writel(mc, mc->soc->intmask, MC_INTMASK); - err = devm_request_irq(&pdev->dev, mc->irq, isr, IRQF_SHARED, + err = devm_request_irq(&pdev->dev, mc->irq, isr, 0, dev_name(&pdev->dev), mc); if (err < 0) { dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", mc->irq, @@ -696,20 +681,65 @@ dev_err(&pdev->dev, "failed to register reset controller: %d\n", err); - if (IS_ENABLED(CONFIG_TEGRA_IOMMU_SMMU)) { + if (IS_ENABLED(CONFIG_TEGRA_IOMMU_SMMU) && mc->soc->smmu) { mc->smmu = tegra_smmu_probe(&pdev->dev, mc->soc->smmu, mc); - if (IS_ERR(mc->smmu)) + if (IS_ERR(mc->smmu)) { dev_err(&pdev->dev, "failed to probe SMMU: %ld\n", PTR_ERR(mc->smmu)); + mc->smmu = NULL; + } + } + + if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && !mc->soc->smmu) { + mc->gart = tegra_gart_probe(&pdev->dev, mc); + if (IS_ERR(mc->gart)) { + dev_err(&pdev->dev, "failed to probe GART: %ld\n", + PTR_ERR(mc->gart)); + mc->gart = NULL; + } } return 0; } +static int tegra_mc_suspend(struct device *dev) +{ + struct tegra_mc *mc = dev_get_drvdata(dev); + int err; + + if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && mc->gart) { + err = tegra_gart_suspend(mc->gart); + if (err) + return err; + } + + return 0; +} + +static int tegra_mc_resume(struct device *dev) +{ + struct tegra_mc *mc = dev_get_drvdata(dev); + int err; + + if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && mc->gart) { + err = tegra_gart_resume(mc->gart); + if (err) + return err; + } + + return 0; +} + +static const struct dev_pm_ops tegra_mc_pm_ops = { + .suspend = tegra_mc_suspend, + .resume = tegra_mc_resume, +}; + static struct platform_driver tegra_mc_driver = { .driver = { .name = "tegra-mc", .of_match_table = tegra_mc_of_match, + .pm = &tegra_mc_pm_ops, .suppress_bind_attrs = true, }, .prevent_deferred_probe = true, -- Gitblit v1.6.2