Memory controller drivers for v7.4

1. Broadcom DPFE: Fix handling kernel memory accesses with malicious or
    compromised firmware and possible out-of-bounds read triggered by
    buggy co-processor.  Also validate firmware image contents before
    processing it.
 
 2. Renesas RPC IF: One fix for volatile register access, several
    cleanups and enable autosuspend in runtime PM.
 
 3. Several minor improvements and fixes for various drivers: TI EMIF,
    Samsung Exynos5422 DMC, Nvidia Tegra264 and STM32 OMM.  The fixes
    seems to be effect of LLM usage, thus they were neither reproduced
    nor tested, making them non-critical fixes.
 
 4. Mediatek SMI: Add support for MT8189 SoC.
 -----BEGIN PGP SIGNATURE-----
 
 iQJEBAABCgAuFiEE3dJiKD0RGyM7briowTdm5oaLg9cFAmrDg/IQHGtyemtAa2Vy
 bmVsLm9yZwAKCRDBN2bmhouD1xTlD/9GsjZZgJFWp9ArVIWvm7eO+g5xWJ6lNq64
 rfG17tpl2hZ2JUWHJRMaCkaocX0CWGpTEUbJm4T120veRI1t1Vbz0X7mJbkeSsfn
 MXlCHroA9SgMws7tbwzneaqKEPeOZ9BLsi0ulg5WMNgUeF25DWS7zFbRRPUOGlKF
 pnyn/w7p32Me8PBJ118eA2ji6eSPciqNVXIQFLFZONLh1AgLjy61E8KzEzZpdHYJ
 txHG47lCRPV7yQZ5RbcL1vcqn9jGNV6E++vGNH/Gcyu+EXN24VJUkOVToLedX/bL
 wvZakHHBAKW8b7Y3raED5VpN0If8pgkTl2Wd/qJ/vfMkIwomLRhOtlDze/+UqDv1
 0QynmM7dkDSyqdTuY0gr00undun3/U/CW/5ReufE0KwFabwzW9vz5cW3TCceXIhH
 E1JvFxW5+Y6wH8kNM1sggDQr23vZ7ITkVQn1m8ooPwA0QGFCJ5yHFEY+eKkeqZMv
 oijL1vrr0lSPFFzL4Rs6ApHbhxn3x3UrBQO82d18qbp8QezN9vbmTF4EmaTw1NCs
 mlJ9F3d4+3vb6ME000kba6qLE6y+czjrAsW5t9Y1hQW3kUqC4CPlIQPBiA4CBPqT
 BuhYEUScs6IMh9z86Ry2Tz6XnQbEwciPdPVGyZUPf8f+HCumqfTBsaAUt3ICrrTY
 sxU5j3laWA==
 =rtEg
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmrOQJYACgkQmmx57+YA
 GNkKrw/+MOk02KXNJHymjGRYo16YMatA4ObQPjXcCZcNmNsMpYwH3WeyLELUmL2L
 mTA9P9Cih/4mANOdFv9qaC7tkhZAVvpQwF8SCRJE4ARuIkG3UEb3D65kkPXwnLnx
 on1P19/ViTkzxMj7TZwomv8yoZHl0eIFIXmYiY3/N4AFGcZczX22wdVwBEINwocw
 12SuaBBYxIalGDzJeoNVxwoLEdUHdKL9lfAHS/lynObw6vJfXJBIckJWWB21h0KJ
 6gNLGjlH7wwtBHGO3BhUZlDcQzm3wy751LO8PfeL8ECkkOPb7X5jRmCUsrwXcxPu
 xuFYIXMZRAC+8NP2FODRaTD/HQOnPPdT0x+IJ5tL5K6pw3A1YYK8oh5zlGPNh+lN
 Iq1+pJB6M4AHjQkzpoJOAN8Tol89VO3UnG1B9fWer2vA2B3jxfSPpbzzfNz2oiPq
 4fcOgACrmGA1IAUS4PzBecmDOOGHtpX2oMW9yrLMTvOMUxlBksx+mqWE6YTvrPAC
 ynhzVL2NTIV6j9A5CMDVOhrb6DrztL6I2bpsP1NeGewUSD8TB/1O3vhF5CMg12WK
 0Qx5P9oescRK+7RjohQ3a4/1xIZFmBGCIsXlkjHuqisJeuz3icIG9x+1xpt2VkZF
 13nF863CvazfYPeFCSuMEnkTUjNfshFyh0EASTt+PumTSAswTeM=
 =BcV3
 -----END PGP SIGNATURE-----

Merge tag 'memory-controller-drv-7.4' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl into soc/drivers

Memory controller drivers for v7.4

1. Broadcom DPFE: Fix handling kernel memory accesses with malicious or
   compromised firmware and possible out-of-bounds read triggered by
   buggy co-processor.  Also validate firmware image contents before
   processing it.

2. Renesas RPC IF: One fix for volatile register access, several
   cleanups and enable autosuspend in runtime PM.

3. Several minor improvements and fixes for various drivers: TI EMIF,
   Samsung Exynos5422 DMC, Nvidia Tegra264 and STM32 OMM.  The fixes
   seems to be effect of LLM usage, thus they were neither reproduced
   nor tested, making them non-critical fixes.

4. Mediatek SMI: Add support for MT8189 SoC.

* tag 'memory-controller-drv-7.4' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl:
  memory: stm32_omm: fix child clock leak on set_amcr() error path
  memory: emif: Remove const from min_tck allocation type
  memory: mtk-smi: Add MT8189 support
  dt-bindings: memory-controllers: mtk-smi: Add support for mt8189
  memory: emif: fix device_node reference leak on np_ddr
  memory: tegra: Refactor Tegra264 mc-err code
  memory: tegra: Parameterise Tegra264 MCF slice bound
  memory: tegra: Use named defines for Tegra264 MC apertures
  memory: exynos5422-dmc: handle clock enable failures
  memory: emif: Replace __ASSEMBLY__ with __ASSEMBLER__ in non-uapi headers
  memory: brcmstb_dpfe: validate firmware section sizes
  memory: renesas-rpc-if: Use runtime PM autosuspend after transfers
  memory: renesas-rpc-if: Consolidate command setup register programming
  memory: renesas-rpc-if: Consolidate XSPI_CDTBUF0 updates in read path
  memory: renesas-rpc-if: Consolidate XSPI_CDTBUF0 updates in write path
  memory: renesas-rpc-if: Move static bridge configurations out of dirmap hot paths
  memory: renesas-rpc-if: Mark XSPI_CDD1BUF0 as volatile
  memory: brcmstb_dpfe: Bounds check DCPU-supplied MSG_ARG_COUNT
  memory: brcmstb_dpfe: Fix out-of-bounds access due to DCPU offset

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
Arnd Bergmann 2026-10-13 16:30:35 +02:00
commit 2699c4615e
10 changed files with 398 additions and 214 deletions

View File

@ -16,7 +16,7 @@ description: |
MediaTek SMI have two generations of HW architecture, here is the list
which generation the SoCs use:
generation 1: mt2701 and mt7623.
generation 2: mt2712, mt6779, mt8167, mt8173, mt8183, mt8186, mt8188, mt8192 and mt8195.
generation 2: mt2712, mt6779, mt8167, mt8173, mt8183, mt8186, mt8188, mt8189, mt8192 and mt8195.
There's slight differences between the two SMI, for generation 2, the
register which control the iommu port is at each larb's register base. But
@ -25,6 +25,21 @@ description: |
SMI generation 1 to transform the smi clock into emi clock domain, but that is
not needed for SMI generation 2.
The smi-common connects with smi-larb and IOMMU. The maximum inputs number of
a smi-common is 8. In SMI generation 2, the engines number may be over 8.
In this case, we use a smi-sub-common to merge some larbs.
The block diagram something is like:
IOMMU
| |
smi-common
---------------------------
| | ...
larb0 sub-common ... <-max number is 8
----------------
| | ...
larb1 larbX ... <-max number is 8
properties:
compatible:
oneOf:
@ -40,6 +55,8 @@ properties:
- mediatek,mt8186-smi-common
- mediatek,mt8188-smi-common-vdo
- mediatek,mt8188-smi-common-vpp
- mediatek,mt8189-smi-common
- mediatek,mt8189-smi-sub-common
- mediatek,mt8192-smi-common
- mediatek,mt8195-smi-common-vdo
- mediatek,mt8195-smi-common-vpp
@ -108,6 +125,7 @@ allOf:
compatible:
contains:
enum:
- mediatek,mt8189-smi-sub-common
- mediatek,mt8195-smi-sub-common
then:
required:
@ -157,6 +175,7 @@ allOf:
- mediatek,mt6795-smi-common
- mediatek,mt8167-smi-common
- mediatek,mt8173-smi-common
- mediatek,mt8189-smi-common
then:
properties:

View File

@ -27,6 +27,7 @@ properties:
- mediatek,mt8183-smi-larb
- mediatek,mt8186-smi-larb
- mediatek,mt8188-smi-larb
- mediatek,mt8189-smi-larb
- mediatek,mt8192-smi-larb
- mediatek,mt8195-smi-larb
@ -85,6 +86,7 @@ allOf:
- mediatek,mt8183-smi-larb
- mediatek,mt8186-smi-larb
- mediatek,mt8188-smi-larb
- mediatek,mt8189-smi-larb
- mediatek,mt8195-smi-larb
then:
@ -119,6 +121,7 @@ allOf:
- mediatek,mt6779-smi-larb
- mediatek,mt8186-smi-larb
- mediatek,mt8188-smi-larb
- mediatek,mt8189-smi-larb
- mediatek,mt8192-smi-larb
- mediatek,mt8195-smi-larb

View File

@ -182,6 +182,8 @@ struct brcmstb_dpfe_priv {
void __iomem *regs;
void __iomem *dmem;
void __iomem *imem;
resource_size_t regs_size;
resource_size_t dmem_size;
struct device *dev;
const struct dpfe_api *dpfe_api;
struct mutex lock;
@ -401,9 +403,14 @@ static void __iomem *get_msg_ptr(struct brcmstb_dpfe_priv *priv, u32 response,
*/
switch (msg_type) {
case 1:
if (DCPU_MSG_RAM_START + offset + DRAM_VENDOR_ERROR +
sizeof(u32) > priv->regs_size)
goto bad_offset;
ptr = priv->regs + DCPU_MSG_RAM_START + offset;
break;
case 0:
if (offset + DRAM_VENDOR_ERROR + sizeof(u32) > priv->dmem_size)
goto bad_offset;
ptr = priv->dmem + offset;
break;
default:
@ -415,6 +422,12 @@ static void __iomem *get_msg_ptr(struct brcmstb_dpfe_priv *priv, u32 response,
}
return ptr;
bad_offset:
dev_err(priv->dev, "DCPU returned out-of-range offset %#x\n", offset);
if (buf && size)
*size = sprintf(buf, "ERROR: DCPU offset out of range\n");
return NULL;
}
static void __finalize_command(struct brcmstb_dpfe_priv *priv)
@ -490,6 +503,8 @@ static int __send_command(struct brcmstb_dpfe_priv *priv, unsigned int cmd,
for (i = 0; i < MSG_FIELD_MAX; i++)
result[i] = readl_relaxed(regs + DCPU_MSG_RAM(i));
chksum_idx = result[MSG_ARG_COUNT] + MSG_ARG_COUNT + 1;
if (chksum_idx >= MSG_FIELD_MAX)
ret = -EINVAL;
}
/* Tell DCPU we are done */
@ -518,9 +533,15 @@ static int __verify_firmware(struct init_data *init,
const struct firmware *fw)
{
const struct dpfe_firmware_header *header = (void *)fw->data;
unsigned int dmem_size, imem_size, total_size;
unsigned int dmem_size, imem_size;
bool is_big_endian = false;
const u32 *chksum_ptr;
size_t payload_size;
if (fw->size < sizeof(*header) + sizeof(*chksum_ptr))
return ERR_INVALID_SIZE;
payload_size = fw->size - sizeof(*header) - sizeof(*chksum_ptr);
if (header->magic == DPFE_BE_MAGIC)
is_big_endian = true;
@ -539,13 +560,8 @@ static int __verify_firmware(struct init_data *init,
if ((dmem_size % sizeof(u32)) != 0 || (imem_size % sizeof(u32)) != 0)
return ERR_INVALID_SIZE;
/*
* The header + the data section + the instruction section + the
* checksum must be equal to the total firmware size.
*/
total_size = dmem_size + imem_size + sizeof(*header) +
sizeof(*chksum_ptr);
if (total_size != fw->size)
/* The data and instruction sections must fill the payload exactly. */
if (dmem_size > payload_size || imem_size != payload_size - dmem_size)
return ERR_INVALID_SIZE;
/* The checksum comes at the very end. */
@ -858,6 +874,7 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct brcmstb_dpfe_priv *priv;
struct resource *res;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@ -869,17 +886,21 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev)
mutex_init(&priv->lock);
platform_set_drvdata(pdev, priv);
priv->regs = devm_platform_ioremap_resource_byname(pdev, "dpfe-cpu");
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dpfe-cpu");
priv->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->regs)) {
dev_err(dev, "couldn't map DCPU registers\n");
return -ENODEV;
}
priv->regs_size = resource_size(res);
priv->dmem = devm_platform_ioremap_resource_byname(pdev, "dpfe-dmem");
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dpfe-dmem");
priv->dmem = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->dmem)) {
dev_err(dev, "Couldn't map DCPU data memory\n");
return -ENOENT;
}
priv->dmem_size = resource_size(res);
priv->imem = devm_platform_ioremap_resource_byname(pdev, "dpfe-imem");
if (IS_ERR(priv->imem)) {

View File

@ -922,6 +922,7 @@ static struct emif_data *of_get_memory_device_details(
if (!emif || !pd || !dev_info) {
dev_err(dev, "%s: Out of memory!!\n",
__func__);
of_node_put(np_ddr);
goto error;
}
@ -946,6 +947,7 @@ static struct emif_data *of_get_memory_device_details(
pd->device_info->io_width, pd->phy_type, pd->ip_rev,
emif->dev)) {
dev_err(dev, "%s: invalid device data!!\n", __func__);
of_node_put(np_ddr);
goto error;
}
/*
@ -1062,7 +1064,8 @@ static struct emif_data *get_device_details(
}
if (pd->min_tck) {
temp = devm_kzalloc(dev, sizeof(*pd->min_tck), GFP_KERNEL);
temp = devm_kzalloc(dev, sizeof(struct lpddr2_min_tck),
GFP_KERNEL);
if (temp) {
memcpy(temp, pd->min_tck, sizeof(*pd->min_tck));
pd->min_tck = temp;
@ -1140,6 +1143,7 @@ static void emif_remove(struct platform_device *pdev)
struct emif_data *emif = platform_get_drvdata(pdev);
emif_debugfs_exit(emif);
of_node_put(emif->np_ddr);
}
static void emif_shutdown(struct platform_device *pdev)

View File

@ -558,7 +558,7 @@
#define EMIF_SRAM_AM33_REG_LAYOUT 0x00000000
#define EMIF_SRAM_AM43_REG_LAYOUT 0x00000001
#ifndef __ASSEMBLY__
#ifndef __ASSEMBLER__
/*
* Structure containing shadow of important registers in EMIF
* The calculation function fills in this structure to be later used for
@ -603,5 +603,5 @@ void ti_emif_enter_sr(void);
void ti_emif_exit_sr(void);
void ti_emif_abort_sr(void);
#endif /* __ASSEMBLY__ */
#endif /* __ASSEMBLER__ */
#endif /* __EMIF_H */

View File

@ -401,6 +401,30 @@ static const u8 mtk_smi_larb_mt8188_ostd[][SMI_LARB_PORT_NR_MAX] = {
[25] = {0x01},
};
static const u8 mtk_smi_larb_mt8189_ostd[][SMI_LARB_PORT_NR_MAX] = {
[0] = {0x8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x10,},
[1] = {0x8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x10,},
[2] = {0x7, 0x7, 0x4, 0x4, 0x1, 0x1, 0x2, 0x2, 0x7, 0x7,},
[4] = {0x2f, 0x1e, 0x9, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x5, 0x1, 0x17,},
[7] = {0x20, 0x2, 0x1, 0x1, 0x1, 0x4, 0x2, 0x1, 0x1, 0x2, 0x3, 0x2,
0xa, 0xf, 0x4, 0x6, 0x5, 0x1,},
[9] = {0x6, 0x3, 0xc, 0x6, 0x1, 0x4, 0x3, 0x1, 0x2, 0x4, 0x5, 0x2,
0x4, 0x2, 0x3, 0xb, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
0x1, 0x1,},
[11] = {0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
0x1, 0x1, 0x1, 0xb, 0x1, 0x4, 0x6, 0x5, 0x6, 0x1, 0x5, 0x2,
0x9, 0x5,},
[13] = {0x2, 0x8, 0x8, 0x8, 0x4, 0x4, 0x4, 0x4, 0x4, 0xe, 0x4, 0x1,
0x6, 0x6, 0x2,},
[14] = {0x1, 0x1, 0x1, 0x20, 0xe, 0x4, 0x8, 0x8, 0x6, 0x4,},
[16] = {0x1e, 0xc, 0x2, 0x8, 0xe, 0x2, 0x1e, 0x10, 0x4, 0x2, 0x2, 0x2,
0x2, 0x2, 0x4, 0x2, 0x4,},
[17] = {0x1e, 0xc, 0x2, 0x8, 0xe, 0x2, 0x1e, 0x10, 0x4, 0x2, 0x2, 0x2,
0x2, 0x2, 0x4, 0x2, 0x4,},
[19] = {0x2, 0x1, 0x3, 0x1,},
[20] = {0x7, 0x7, 0x3, 0x3, 0x1, 0x1,},
};
static const u8 mtk_smi_larb_mt8192_ostd[][SMI_LARB_PORT_NR_MAX] = {
[0] = {0x2, 0x2, 0x28, 0xa, 0xc, 0x28,},
[1] = {0x2, 0x2, 0x18, 0x18, 0x18, 0xa, 0xc, 0x28,},
@ -533,6 +557,13 @@ static const struct mtk_smi_larb_gen mtk_smi_larb_mt8188 = {
.ostd = mtk_smi_larb_mt8188_ostd,
};
static const struct mtk_smi_larb_gen mtk_smi_larb_mt8189 = {
.config_port = mtk_smi_larb_config_port_gen2_general,
.flags_general = MTK_SMI_FLAG_THRT_UPDATE | MTK_SMI_FLAG_SW_FLAG |
MTK_SMI_FLAG_SLEEP_CTL | MTK_SMI_FLAG_CFG_PORT_SEC_CTL,
.ostd = mtk_smi_larb_mt8189_ostd,
};
static const struct mtk_smi_larb_gen mtk_smi_larb_mt8192 = {
.config_port = mtk_smi_larb_config_port_gen2_general,
.ostd = mtk_smi_larb_mt8192_ostd,
@ -556,6 +587,7 @@ static const struct of_device_id mtk_smi_larb_of_ids[] = {
{.compatible = "mediatek,mt8183-smi-larb", .data = &mtk_smi_larb_mt8183},
{.compatible = "mediatek,mt8186-smi-larb", .data = &mtk_smi_larb_mt8186},
{.compatible = "mediatek,mt8188-smi-larb", .data = &mtk_smi_larb_mt8188},
{.compatible = "mediatek,mt8189-smi-larb", .data = &mtk_smi_larb_mt8189},
{.compatible = "mediatek,mt8192-smi-larb", .data = &mtk_smi_larb_mt8192},
{.compatible = "mediatek,mt8195-smi-larb", .data = &mtk_smi_larb_mt8195},
{}
@ -808,6 +840,17 @@ static const struct mtk_smi_common_plat mtk_smi_common_mt8188_vpp = {
.init = mtk_smi_common_mt8195_init,
};
static const struct mtk_smi_common_plat mtk_smi_common_mt8189 = {
.type = MTK_SMI_GEN2,
.bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(3) | F_MMU1_LARB(5) |
F_MMU1_LARB(7),
};
static const struct mtk_smi_common_plat mtk_smi_sub_common_mt8189 = {
.type = MTK_SMI_GEN2_SUB_COMM,
.has_gals = true,
};
static const struct mtk_smi_common_plat mtk_smi_common_mt8192 = {
.type = MTK_SMI_GEN2,
.has_gals = true,
@ -852,6 +895,8 @@ static const struct of_device_id mtk_smi_common_of_ids[] = {
{.compatible = "mediatek,mt8186-smi-common", .data = &mtk_smi_common_mt8186},
{.compatible = "mediatek,mt8188-smi-common-vdo", .data = &mtk_smi_common_mt8188_vdo},
{.compatible = "mediatek,mt8188-smi-common-vpp", .data = &mtk_smi_common_mt8188_vpp},
{.compatible = "mediatek,mt8189-smi-common", .data = &mtk_smi_common_mt8189},
{.compatible = "mediatek,mt8189-smi-sub-common", .data = &mtk_smi_sub_common_mt8189},
{.compatible = "mediatek,mt8192-smi-common", .data = &mtk_smi_common_mt8192},
{.compatible = "mediatek,mt8195-smi-common-vdo", .data = &mtk_smi_common_mt8195_vdo},
{.compatible = "mediatek,mt8195-smi-common-vpp", .data = &mtk_smi_common_mt8195_vpp},

View File

@ -34,6 +34,7 @@ static const struct regmap_access_table rpcif_volatile_table = {
static const struct regmap_range xspi_volatile_ranges[] = {
regmap_reg_range(XSPI_CDD0BUF0, XSPI_CDD0BUF0),
regmap_reg_range(XSPI_CDD1BUF0, XSPI_CDD1BUF0),
};
static const struct regmap_access_table xspi_volatile_table = {
@ -311,6 +312,14 @@ static int xspi_hw_init_impl(struct rpcif_priv *xspi, bool hyperflash)
regmap_update_bits(xspi->regmap, XSPI_INTE, XSPI_INTE_CMDCMPE,
XSPI_INTE_CMDCMPE);
regmap_update_bits(xspi->regmap, XSPI_BMCTL0,
XSPI_BMCTL0_CS0ACC(0xff), XSPI_BMCTL0_CS0ACC(0x03));
regmap_update_bits(xspi->regmap, XSPI_BMCFG,
XSPI_BMCFG_WRMD | XSPI_BMCFG_MWRCOMB |
XSPI_BMCFG_MWRSIZE(0xff) | XSPI_BMCFG_PREEN,
0 | XSPI_BMCFG_MWRCOMB | XSPI_BMCFG_MWRSIZE(0x0f) |
XSPI_BMCFG_PREEN);
return 0;
}
@ -627,18 +636,14 @@ static int xspi_manual_xfer_impl(struct rpcif_priv *xspi)
u32 pos = 0, max = 8;
int ret = 0;
regmap_update_bits(xspi->regmap, XSPI_CDCTL0, XSPI_CDCTL0_TRNUM(0x3),
/* Clear transaction number and request */
regmap_update_bits(xspi->regmap, XSPI_CDCTL0,
XSPI_CDCTL0_TRNUM(0x3) | XSPI_CDCTL0_TRREQ,
XSPI_CDCTL0_TRNUM(0));
regmap_update_bits(xspi->regmap, XSPI_CDCTL0, XSPI_CDCTL0_TRREQ, 0);
regmap_write(xspi->regmap, XSPI_CDTBUF0,
XSPI_CDTBUF_CMDSIZE(0x1) | XSPI_CDTBUF_CMD_FIELD(xspi->command));
regmap_write(xspi->regmap, XSPI_CDABUF0, 0);
regmap_update_bits(xspi->regmap, XSPI_CDTBUF0, XSPI_CDTBUF_ADDSIZE(0x7),
XSPI_CDTBUF_ADDSIZE(xspi->addr_nbytes));
XSPI_CDTBUF_CMDSIZE(0x1) | XSPI_CDTBUF_CMD_FIELD(xspi->command) |
XSPI_CDTBUF_ADDSIZE(xspi->addr_nbytes));
regmap_write(xspi->regmap, XSPI_CDABUF0, xspi->smadr);
@ -651,17 +656,12 @@ static int xspi_manual_xfer_impl(struct rpcif_priv *xspi)
u32 bytes_left = xspi->xferlen - pos;
u32 nbytes, data[2], *p = data;
regmap_update_bits(xspi->regmap, XSPI_CDTBUF0,
XSPI_CDTBUF_TRTYPE, XSPI_CDTBUF_TRTYPE);
nbytes = bytes_left >= max ? max : bytes_left;
regmap_update_bits(xspi->regmap, XSPI_CDTBUF0,
XSPI_CDTBUF_DATASIZE(0xf),
XSPI_CDTBUF_DATASIZE(nbytes));
regmap_update_bits(xspi->regmap, XSPI_CDTBUF0,
XSPI_CDTBUF_TRTYPE | XSPI_CDTBUF_DATASIZE(0xf) |
XSPI_CDTBUF_ADDSIZE(0x7),
XSPI_CDTBUF_TRTYPE | XSPI_CDTBUF_DATASIZE(nbytes) |
XSPI_CDTBUF_ADDSIZE(xspi->addr_nbytes));
memcpy(data, xspi->buffer + pos, nbytes);
@ -693,30 +693,33 @@ static int xspi_manual_xfer_impl(struct rpcif_priv *xspi)
while (pos < xspi->xferlen) {
u32 bytes_left = xspi->xferlen - pos;
u32 nbytes, data[2], *p = data;
regmap_update_bits(xspi->regmap, XSPI_CDTBUF0,
XSPI_CDTBUF_TRTYPE,
~(u32)XSPI_CDTBUF_TRTYPE);
u32 cdtbuf0_mask, cdtbuf0_val;
/* nbytes can be up to 8 bytes */
nbytes = bytes_left >= max ? max : bytes_left;
regmap_update_bits(xspi->regmap, XSPI_CDTBUF0,
XSPI_CDTBUF_DATASIZE(0xf),
XSPI_CDTBUF_DATASIZE(nbytes));
/* clear TRTYPE */
cdtbuf0_mask = XSPI_CDTBUF_TRTYPE;
cdtbuf0_val = 0;
regmap_update_bits(xspi->regmap, XSPI_CDTBUF0,
XSPI_CDTBUF_ADDSIZE(0x7),
XSPI_CDTBUF_ADDSIZE(xspi->addr_nbytes));
/* program DATASIZE */
cdtbuf0_mask |= XSPI_CDTBUF_DATASIZE(0xf);
cdtbuf0_val |= XSPI_CDTBUF_DATASIZE(nbytes);
/* program ADDSIZE */
cdtbuf0_mask |= XSPI_CDTBUF_ADDSIZE(0x7);
cdtbuf0_val |= XSPI_CDTBUF_ADDSIZE(xspi->addr_nbytes);
/* program LATE */
cdtbuf0_mask |= XSPI_CDTBUF_LATE(0x1f);
cdtbuf0_val |= XSPI_CDTBUF_LATE(xspi->dummy);
regmap_update_bits(xspi->regmap, XSPI_CDTBUF0, cdtbuf0_mask, cdtbuf0_val);
if (xspi->addr_nbytes)
regmap_write(xspi->regmap, XSPI_CDABUF0,
xspi->smadr + pos);
regmap_update_bits(xspi->regmap, XSPI_CDTBUF0,
XSPI_CDTBUF_LATE(0x1f),
XSPI_CDTBUF_LATE(xspi->dummy));
regmap_update_bits(xspi->regmap, XSPI_CDCTL0,
XSPI_CDCTL0_TRREQ, XSPI_CDCTL0_TRREQ);
@ -773,7 +776,7 @@ int rpcif_manual_xfer(struct device *dev)
ret = rpc->info->impl->manual_xfer(rpc);
pm_runtime_put(dev);
pm_runtime_put_autosuspend(dev);
return ret;
}
@ -868,15 +871,6 @@ static size_t xspi_dirmap_read_impl(struct rpcif_priv *xspi, u64 offs,
XSPI_CMCFG1_RDCMD_UPPER_BYTE(xspi->command) |
XSPI_CMCFG1_RDLATE(xspi->dummy));
regmap_update_bits(xspi->regmap, XSPI_BMCTL0, XSPI_BMCTL0_CS0ACC(0xff),
XSPI_BMCTL0_CS0ACC(0x01));
regmap_update_bits(xspi->regmap, XSPI_BMCFG,
XSPI_BMCFG_WRMD | XSPI_BMCFG_MWRCOMB |
XSPI_BMCFG_MWRSIZE(0xff) | XSPI_BMCFG_PREEN,
0 | XSPI_BMCFG_MWRCOMB | XSPI_BMCFG_MWRSIZE(0x0f) |
XSPI_BMCFG_PREEN);
regmap_update_bits(xspi->regmap, XSPI_LIOCFGCS0, XSPI_LIOCFG_PRTMD(0x3ff),
XSPI_LIOCFG_PRTMD(xspi->proto));
@ -897,7 +891,7 @@ ssize_t rpcif_dirmap_read(struct device *dev, u64 offs, size_t len, void *buf)
read = rpc->info->impl->dirmap_read(rpc, offs, len, buf);
pm_runtime_put(dev);
pm_runtime_put_autosuspend(dev);
return read;
}
@ -944,15 +938,6 @@ ssize_t xspi_dirmap_write(struct device *dev, u64 offs, size_t len, const void *
XSPI_CMCFG2_WRCMD_UPPER(xspi->command) |
XSPI_CMCFG2_WRLATE(xspi->dummy));
regmap_update_bits(xspi->regmap, XSPI_BMCTL0,
XSPI_BMCTL0_CS0ACC(0xff), XSPI_BMCTL0_CS0ACC(0x03));
regmap_update_bits(xspi->regmap, XSPI_BMCFG,
XSPI_BMCFG_WRMD | XSPI_BMCFG_MWRCOMB |
XSPI_BMCFG_MWRSIZE(0xff) | XSPI_BMCFG_PREEN,
0 | XSPI_BMCFG_MWRCOMB | XSPI_BMCFG_MWRSIZE(0x0f) |
XSPI_BMCFG_PREEN);
regmap_update_bits(xspi->regmap, XSPI_LIOCFGCS0, XSPI_LIOCFG_PRTMD(0x3ff),
XSPI_LIOCFG_PRTMD(xspi->proto));
@ -963,7 +948,7 @@ ssize_t xspi_dirmap_write(struct device *dev, u64 offs, size_t len, const void *
regmap_update_bits(xspi->regmap, XSPI_BMCTL1,
XSPI_BMCTL1_MWRPUSH, XSPI_BMCTL1_MWRPUSH);
pm_runtime_put(dev);
pm_runtime_put_autosuspend(dev);
return writebytes;
}

View File

@ -1297,8 +1297,15 @@ static int exynos5_dmc_init_clks(struct exynos5_dmc *dmc)
if (ret)
return ret;
clk_prepare_enable(dmc->fout_bpll);
clk_prepare_enable(dmc->mout_bpll);
ret = clk_prepare_enable(dmc->fout_bpll);
if (ret)
return ret;
ret = clk_prepare_enable(dmc->mout_bpll);
if (ret) {
clk_disable_unprepare(dmc->fout_bpll);
return ret;
}
/*
* Some bootloaders do not set clock routes correctly.

View File

@ -274,6 +274,8 @@ static int stm32_omm_configure(struct device *dev)
writel_relaxed(omm->cr, omm->io_base + OMM_CR);
ret = stm32_omm_set_amcr(dev, true);
if (ret && (mux & CR_MUXEN))
stm32_omm_toggle_child_clock(dev, false);
error:
pm_runtime_put_sync_suspend(dev);

View File

@ -15,6 +15,47 @@
#include "mc.h"
#include "tegra264-bwmgr.h"
/*
* Description of a single MCF error type: where to read the status and the
* faulting address, how to extract the high address bits, which bits encode
* the access direction and security state and the optional error-type sub-code.
*/
struct tegra264_mc_fault {
const char *const *type_names;
u32 addr_hi_mask;
u32 addr_hi_reg;
u32 addr_hi_shift;
u32 addr_reg;
u32 rw_bit;
u32 sec_bit;
u32 status1_reg;
u32 status_reg;
u32 type_mask;
u32 type_shift;
};
/*
* Maps an MCF interrupt to a callback that fills in the register offsets and
* decoding parameters for that error type. The register offsets live in the
* per-SoC tegra_mc_regs, so they are collected at runtime rather than being
* stored in a static table.
*/
struct tegra264_mc_error_handler {
u32 mask;
void (*get_offsets)(struct tegra_mc *mc, struct tegra264_mc_fault *fault);
};
/*
* Description of a single HUB error type. addr_reg is zero for error types
* that don't latch a fault address.
*/
struct tegra264_hub_error_handler {
u32 addr_hi_reg;
u32 addr_reg;
u32 mask;
u32 status_reg;
};
/*
* MC Client entries are sorted in the increasing order of the
* override and security register offsets.
@ -717,11 +758,18 @@ static const char *const tegra264_rt_error_names[16] = {
};
/*
* MC instance aperture mapping for hubc registers
* On Tegra264 the memory controller error interrupts are distributed across
* several HUB/HUBC apertures. Each aperture is accessed like a broadcast
* channel through mc_ch_readl()/mc_ch_writel() using its fixed index.
*/
static const int mc_hubc_aperture_number[5] = {
7, 8, 9, 10, 11
};
#define TEGRA264_MC_APERTURE_DISP 7
#define TEGRA264_MC_APERTURE_SYSTEM 8
#define TEGRA264_MC_APERTURE_VISION 9
#define TEGRA264_MC_APERTURE_UPHY 10
#define TEGRA264_MC_APERTURE_TOP 11
/* Tegra264 splits the MCF common interrupt status across five slices. */
#define TEGRA264_MC_NUM_SLICES 5
/*
* tegra264_mc_icc_set() - Pass MC client info to the BPMP-FW
@ -807,115 +855,149 @@ static int tegra264_mc_icc_get_init_bw(struct icc_node *node, u32 *avg, u32 *pea
return 0;
}
static void tegra264_mc_fault_emem(struct tegra_mc *mc, struct tegra264_mc_fault *fault)
{
fault->status_reg = mc->soc->regs->err_status;
fault->addr_reg = mc->soc->regs->err_add;
fault->addr_hi_reg = mc->soc->regs->err_add_hi;
fault->type_mask = mc->soc->mc_err_status_type_mask;
fault->type_shift = MC_ERR_STATUS_TYPE_SHIFT;
fault->type_names = tegra264_mc_error_names;
}
static void tegra264_mc_fault_vpr(struct tegra_mc *mc, struct tegra264_mc_fault *fault)
{
fault->status_reg = mc->soc->regs->err_vpr_status;
fault->addr_reg = mc->soc->regs->err_vpr_add;
fault->addr_hi_shift = MC_ERR_STATUS_ADR_HI_SHIFT;
fault->addr_hi_mask = mc->soc->mc_addr_hi_mask;
}
static void tegra264_mc_fault_sec(struct tegra_mc *mc, struct tegra264_mc_fault *fault)
{
fault->status_reg = mc->soc->regs->err_sec_status;
fault->addr_reg = mc->soc->regs->err_sec_add;
fault->addr_hi_shift = MC_ERR_STATUS_ADR_HI_SHIFT;
fault->addr_hi_mask = mc->soc->mc_addr_hi_mask;
}
static void tegra264_mc_fault_mts(struct tegra_mc *mc, struct tegra264_mc_fault *fault)
{
fault->status_reg = mc->soc->regs->err_mts_status;
fault->addr_reg = mc->soc->regs->err_mts_add;
fault->addr_hi_shift = MC_ERR_STATUS_ADR_HI_SHIFT;
fault->addr_hi_mask = mc->soc->mc_addr_hi_mask;
}
static void tegra264_mc_fault_gsc(struct tegra_mc *mc, struct tegra264_mc_fault *fault)
{
fault->status_reg = mc->soc->regs->err_gen_co_status;
fault->status1_reg = MC_ERR_GENERALIZED_CARVEOUT_STATUS_1_0;
fault->addr_reg = mc->soc->regs->err_gen_co_add;
fault->addr_hi_shift = MC_ERR_STATUS_GSC_ADR_HI_SHIFT;
fault->addr_hi_mask = MC_ERR_STATUS_GSC_ADR_HI_MASK;
}
static void tegra264_mc_fault_route(struct tegra_mc *mc, struct tegra264_mc_fault *fault)
{
fault->status_reg = mc->soc->regs->err_route_status;
fault->addr_reg = mc->soc->regs->err_route_add;
fault->addr_hi_shift = MC_ERR_STATUS_RT_ADR_HI_SHIFT;
fault->addr_hi_mask = mc->soc->mc_addr_hi_mask;
fault->rw_bit = MC_ERR_ROUTE_SANITY_RW;
fault->sec_bit = MC_ERR_ROUTE_SANITY_SEC;
fault->type_mask = MC_ERR_STATUS_RT_TYPE_MASK;
fault->type_shift = MC_ERR_STATUS_RT_TYPE_SHIFT;
fault->type_names = tegra264_rt_error_names;
}
static const struct tegra264_mc_error_handler tegra264_mc_error_handlers[] = {
{ MC_INT_DECERR_EMEM, tegra264_mc_fault_emem },
{ MC_INT_SECURITY_VIOLATION, tegra264_mc_fault_emem },
{ MC_INT_DECERR_VPR, tegra264_mc_fault_vpr },
{ MC_INT_SECERR_SEC, tegra264_mc_fault_sec },
{ MC_INT_DECERR_MTS, tegra264_mc_fault_mts },
{ MC_INT_DECERR_GENERALIZED_CARVEOUT, tegra264_mc_fault_gsc },
{ MC_INT_DECERR_ROUTE_SANITY, tegra264_mc_fault_route },
{ MC_INT_DECERR_ROUTE_SANITY_GIC_MSI, tegra264_mc_fault_route },
};
static void tegra264_mc_report_fault(struct tegra_mc *mc, u32 channel,
unsigned int interrupt,
const struct tegra264_mc_fault *fault)
{
const char *client = "unknown", *desc = "NA";
u32 value, client_id, status1 = 0;
phys_addr_t addr = 0;
unsigned int i;
u8 type;
value = mc_ch_readl(mc, channel, fault->status_reg);
if (fault->addr_hi_reg) {
addr = mc_ch_readl(mc, channel, fault->addr_hi_reg);
} else if (fault->status1_reg) {
status1 = mc_ch_readl(mc, channel, fault->status1_reg);
addr = (status1 >> fault->addr_hi_shift) & fault->addr_hi_mask;
} else {
addr = (value >> fault->addr_hi_shift) & fault->addr_hi_mask;
}
addr <<= 32;
addr |= mc_ch_readl(mc, channel, fault->addr_reg);
client_id = value & mc->soc->client_id_mask;
for (i = 0; i < mc->soc->num_clients; i++) {
if (mc->soc->clients[i].id == client_id) {
client = mc->soc->clients[i].name;
break;
}
}
if (fault->type_names) {
type = (value & fault->type_mask) >> fault->type_shift;
desc = fault->type_names[type];
}
dev_err_ratelimited(mc->dev, "%s: %s %s @%pa: %s (%s)\n",
client, value & fault->sec_bit ? "secure" : "non-secure",
value & fault->rw_bit ? "write" : "read", &addr,
tegra_mc_status_names[interrupt] ?: "unknown", desc);
if (fault->status1_reg)
dev_err_ratelimited(mc->dev, "gsc_apr_id=%u gsc_co_apr_id=%u\n",
(status1 >> ERR_GENERALIZED_APERTURE_ID_SHIFT) &
ERR_GENERALIZED_APERTURE_ID_MASK,
(status1 >> ERR_GENERALIZED_CARVEOUT_APERTURE_ID_SHIFT) &
ERR_GENERALIZED_CARVEOUT_APERTURE_ID_MASK);
}
static void mcf_log_fault(struct tegra_mc *mc, u32 channel, unsigned long mcf_ch_intstatus)
{
unsigned int bit;
unsigned int interrupt;
for_each_set_bit(bit, &mcf_ch_intstatus, 32) {
const char *client = "unknown", *desc = "NA";
u32 status_reg, status1_reg = 0, addr_reg, addr_hi_reg = 0, err_type_mask = 0;
u32 value, client_id, i, addr_hi_shift = 0, addr_hi_mask = 0, status1;
u32 mc_rw_bit = MC_ERR_STATUS_RW, mc_sec_bit = MC_ERR_STATUS_SECURITY;
phys_addr_t addr = 0;
u8 type;
for_each_set_bit(interrupt, &mcf_ch_intstatus, 32) {
const struct tegra264_mc_error_handler *handler = NULL;
struct tegra264_mc_fault fault = {
.rw_bit = MC_ERR_STATUS_RW,
.sec_bit = MC_ERR_STATUS_SECURITY,
};
unsigned int i;
switch (BIT(bit)) {
case MC_INT_DECERR_EMEM:
case MC_INT_SECURITY_VIOLATION:
status_reg = mc->soc->regs->err_status;
addr_reg = mc->soc->regs->err_add;
addr_hi_reg = mc->soc->regs->err_add_hi;
err_type_mask = mc->soc->mc_err_status_type_mask;
break;
case MC_INT_DECERR_VPR:
status_reg = mc->soc->regs->err_vpr_status;
addr_reg = mc->soc->regs->err_vpr_add;
addr_hi_shift = MC_ERR_STATUS_ADR_HI_SHIFT;
addr_hi_mask = mc->soc->mc_addr_hi_mask;
break;
case MC_INT_SECERR_SEC:
status_reg = mc->soc->regs->err_sec_status;
addr_reg = mc->soc->regs->err_sec_add;
addr_hi_shift = MC_ERR_STATUS_ADR_HI_SHIFT;
addr_hi_mask = mc->soc->mc_addr_hi_mask;
break;
case MC_INT_DECERR_MTS:
status_reg = mc->soc->regs->err_mts_status;
addr_reg = mc->soc->regs->err_mts_add;
addr_hi_shift = MC_ERR_STATUS_ADR_HI_SHIFT;
addr_hi_mask = mc->soc->mc_addr_hi_mask;
break;
case MC_INT_DECERR_GENERALIZED_CARVEOUT:
status_reg = mc->soc->regs->err_gen_co_status;
status1_reg = MC_ERR_GENERALIZED_CARVEOUT_STATUS_1_0;
addr_reg = mc->soc->regs->err_gen_co_add;
addr_hi_shift = MC_ERR_STATUS_GSC_ADR_HI_SHIFT;
addr_hi_mask = MC_ERR_STATUS_GSC_ADR_HI_MASK;
break;
case MC_INT_DECERR_ROUTE_SANITY:
case MC_INT_DECERR_ROUTE_SANITY_GIC_MSI:
status_reg = mc->soc->regs->err_route_status;
addr_reg = mc->soc->regs->err_route_add;
addr_hi_shift = MC_ERR_STATUS_RT_ADR_HI_SHIFT;
addr_hi_mask = mc->soc->mc_addr_hi_mask;
mc_sec_bit = MC_ERR_ROUTE_SANITY_SEC;
mc_rw_bit = MC_ERR_ROUTE_SANITY_RW;
err_type_mask = MC_ERR_STATUS_RT_TYPE_MASK;
break;
default:
dev_err_ratelimited(mc->dev, "Incorrect MC interrupt mask\n");
return;
}
value = mc_ch_readl(mc, channel, status_reg);
if (addr_hi_reg) {
addr = mc_ch_readl(mc, channel, addr_hi_reg);
} else {
if (!status1_reg) {
addr = ((value >> addr_hi_shift) & addr_hi_mask);
} else {
status1 = mc_ch_readl(mc, channel, status1_reg);
addr = ((status1 >> addr_hi_shift) & addr_hi_mask);
}
}
addr <<= 32;
addr |= mc_ch_readl(mc, channel, addr_reg);
client_id = value & mc->soc->client_id_mask;
for (i = 0; i < mc->soc->num_clients; i++) {
if (mc->soc->clients[i].id == client_id) {
client = mc->soc->clients[i].name;
for (i = 0; i < ARRAY_SIZE(tegra264_mc_error_handlers); i++) {
if (tegra264_mc_error_handlers[i].mask == BIT(interrupt)) {
handler = &tegra264_mc_error_handlers[i];
break;
}
}
if (err_type_mask == MC_ERR_STATUS_RT_TYPE_MASK) {
type = (value & err_type_mask) >>
MC_ERR_STATUS_RT_TYPE_SHIFT;
desc = tegra264_rt_error_names[type];
} else if (err_type_mask) {
type = (value & err_type_mask) >>
MC_ERR_STATUS_TYPE_SHIFT;
desc = tegra264_mc_error_names[type];
if (!handler) {
dev_err_ratelimited(mc->dev, "Incorrect MC interrupt mask\n");
return;
}
dev_err_ratelimited(mc->dev, "%s: %s %s @%pa: %s (%s)\n",
client, value & mc_sec_bit ? "secure" : "non-secure",
value & mc_rw_bit ? "write" : "read", &addr,
tegra_mc_status_names[bit] ?: "unknown", desc);
if (status1_reg)
dev_err_ratelimited(mc->dev, "gsc_apr_id=%u gsc_co_apr_id=%u\n",
((status1 >> ERR_GENERALIZED_APERTURE_ID_SHIFT)
& ERR_GENERALIZED_APERTURE_ID_MASK),
((status1 >> ERR_GENERALIZED_CARVEOUT_APERTURE_ID_SHIFT)
& ERR_GENERALIZED_CARVEOUT_APERTURE_ID_MASK));
handler->get_offsets(mc, &fault);
tegra264_mc_report_fault(mc, channel, interrupt, &fault);
}
/* clear interrupts */
@ -937,7 +1019,7 @@ static irqreturn_t handle_mcf_irq(int irq, void *data)
for_each_set_bit(slice, &common_intstat, 32) {
/* Find out the slice number on which interrupt occurred */
if (slice > 4) {
if (slice >= TEGRA264_MC_NUM_SLICES) {
dev_err(mc->dev, "Slice index out of bounds: %u\n", slice);
return IRQ_NONE;
}
@ -950,53 +1032,69 @@ static irqreturn_t handle_mcf_irq(int irq, void *data)
return IRQ_HANDLED;
}
static const struct tegra264_hub_error_handler tegra264_hub_error_handlers[] = {
{
.mask = MSS_HUB_COALESCER_ERR_INTMASK,
.status_reg = MSS_HUB_COALESCE_ERR_STATUS_0,
.addr_reg = MSS_HUB_COALESCE_ERR_ADR_0,
.addr_hi_reg = MSS_HUB_COALESCE_ERR_ADR_HI_0,
},
{
.mask = MSS_HUB_SMMU_BYPASS_ALLOW_ERR_INTMASK,
.status_reg = MSS_HUB_SMMU_BYPASS_ALLOW_ERR_STATUS_0,
},
{
.mask = MSS_HUB_ILLEGAL_TBUGRP_ID_INTMASK,
.status_reg = MSS_HUB_ILLEGAL_TBUGRP_ID_ERR_STATUS_0,
},
{
.mask = MSS_HUB_MSI_ERR_INTMASK,
.status_reg = MSS_HUB_MSI_ERR_STATUS_0,
},
{
.mask = MSS_HUB_POISON_RSP_INTMASK,
.status_reg = MSS_HUB_POISON_RSP_STATUS_0,
},
{
.mask = MSS_HUB_RESTRICTED_ACCESS_ERR_INTMASK,
.status_reg = MSS_HUB_RESTRICTED_ACCESS_ERR_STATUS_0,
},
{
.mask = MSS_HUB_RESERVED_PA_ERR_INTMASK,
.status_reg = MSS_HUB_RESERVED_PA_ERR_STATUS_0,
},
};
static void hub_log_fault(struct tegra_mc *mc, u32 hub, unsigned long hub_intstat)
{
unsigned int bit;
unsigned int interrupt;
for_each_set_bit(bit, &hub_intstat, 32) {
for_each_set_bit(interrupt, &hub_intstat, 32) {
const struct tegra264_hub_error_handler *handler = NULL;
const char *client = "unknown";
u32 client_id, status_reg, value, i;
u32 client_id, value;
phys_addr_t addr = 0;
unsigned int i;
switch (BIT(bit)) {
case MSS_HUB_COALESCER_ERR_INTMASK:
status_reg = MSS_HUB_COALESCE_ERR_STATUS_0;
addr = mc_ch_readl(mc, hub, MSS_HUB_COALESCE_ERR_ADR_HI_0);
addr <<= 32;
addr |= mc_ch_readl(mc, hub, MSS_HUB_COALESCE_ERR_ADR_0);
break;
for (i = 0; i < ARRAY_SIZE(tegra264_hub_error_handlers); i++) {
if (tegra264_hub_error_handlers[i].mask == BIT(interrupt)) {
handler = &tegra264_hub_error_handlers[i];
break;
}
}
case MSS_HUB_SMMU_BYPASS_ALLOW_ERR_INTMASK:
status_reg = MSS_HUB_SMMU_BYPASS_ALLOW_ERR_STATUS_0;
break;
case MSS_HUB_ILLEGAL_TBUGRP_ID_INTMASK:
status_reg = MSS_HUB_ILLEGAL_TBUGRP_ID_ERR_STATUS_0;
break;
case MSS_HUB_MSI_ERR_INTMASK:
status_reg = MSS_HUB_MSI_ERR_STATUS_0;
break;
case MSS_HUB_POISON_RSP_INTMASK:
status_reg = MSS_HUB_POISON_RSP_STATUS_0;
break;
case MSS_HUB_RESTRICTED_ACCESS_ERR_INTMASK:
status_reg = MSS_HUB_RESTRICTED_ACCESS_ERR_STATUS_0;
break;
case MSS_HUB_RESERVED_PA_ERR_INTMASK:
status_reg = MSS_HUB_RESERVED_PA_ERR_STATUS_0;
break;
default:
if (!handler) {
dev_err_ratelimited(mc->dev, "Incorrect HUB interrupt mask\n");
return;
}
value = mc_ch_readl(mc, hub, status_reg);
if (handler->addr_reg) {
addr = mc_ch_readl(mc, hub, handler->addr_hi_reg);
addr <<= 32;
addr |= mc_ch_readl(mc, hub, handler->addr_reg);
}
value = mc_ch_readl(mc, hub, handler->status_reg);
client_id = value & mc->soc->client_id_mask;
for (i = 0; i < mc->soc->num_clients; i++) {
@ -1007,8 +1105,8 @@ static void hub_log_fault(struct tegra_mc *mc, u32 hub, unsigned long hub_intsta
}
dev_err_ratelimited(mc->dev, "%s: @%pa: %s status: 0x%x\n",
client, &addr, tegra264_hub_error_names[bit] ?: "unknown",
value);
client, &addr,
tegra264_hub_error_names[interrupt] ?: "unknown", value);
}
/* clear interrupts */
@ -1057,27 +1155,27 @@ static irqreturn_t handle_hub_irq(int irq, void *data, int mc_hubc_aperture_numb
static irqreturn_t handle_disp_hub_irq(int irq, void *data)
{
return handle_hub_irq(irq, data, mc_hubc_aperture_number[0]);
return handle_hub_irq(irq, data, TEGRA264_MC_APERTURE_DISP);
}
static irqreturn_t handle_system_hub_irq(int irq, void *data)
{
return handle_hub_irq(irq, data, mc_hubc_aperture_number[1]);
return handle_hub_irq(irq, data, TEGRA264_MC_APERTURE_SYSTEM);
}
static irqreturn_t handle_vision_hub_irq(int irq, void *data)
{
return handle_hub_irq(irq, data, mc_hubc_aperture_number[2]);
return handle_hub_irq(irq, data, TEGRA264_MC_APERTURE_VISION);
}
static irqreturn_t handle_uphy_hub_irq(int irq, void *data)
{
return handle_hub_irq(irq, data, mc_hubc_aperture_number[3]);
return handle_hub_irq(irq, data, TEGRA264_MC_APERTURE_UPHY);
}
static irqreturn_t handle_top_hub_irq(int irq, void *data)
{
return handle_hub_irq(irq, data, mc_hubc_aperture_number[4]);
return handle_hub_irq(irq, data, TEGRA264_MC_APERTURE_TOP);
}
static irqreturn_t handle_generic_irq(struct tegra_mc *mc, unsigned long intstat_reg)