diff --git a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.yaml b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.yaml index 0762e0ff66ef..33c989f7fc33 100644 --- a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.yaml @@ -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: diff --git a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.yaml b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.yaml index 2e7fac4b5094..9a5dafd7c07e 100644 --- a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.yaml @@ -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 diff --git a/drivers/memory/brcmstb_dpfe.c b/drivers/memory/brcmstb_dpfe.c index 08d9e05b1b33..04ae3cfb449e 100644 --- a/drivers/memory/brcmstb_dpfe.c +++ b/drivers/memory/brcmstb_dpfe.c @@ -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)) { diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c index 2fadad0666b1..886c2ca0dc19 100644 --- a/drivers/memory/emif.c +++ b/drivers/memory/emif.c @@ -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) diff --git a/drivers/memory/emif.h b/drivers/memory/emif.h index 55aeb36a5bf2..5dfb09adb096 100644 --- a/drivers/memory/emif.h +++ b/drivers/memory/emif.h @@ -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 */ diff --git a/drivers/memory/mtk-smi.c b/drivers/memory/mtk-smi.c index aaeba8ab211e..8c4606cbd73d 100644 --- a/drivers/memory/mtk-smi.c +++ b/drivers/memory/mtk-smi.c @@ -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}, diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c index 3755956ae906..ec901a5a99aa 100644 --- a/drivers/memory/renesas-rpc-if.c +++ b/drivers/memory/renesas-rpc-if.c @@ -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; } diff --git a/drivers/memory/samsung/exynos5422-dmc.c b/drivers/memory/samsung/exynos5422-dmc.c index 788d49c688b1..98c319552583 100644 --- a/drivers/memory/samsung/exynos5422-dmc.c +++ b/drivers/memory/samsung/exynos5422-dmc.c @@ -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. diff --git a/drivers/memory/stm32_omm.c b/drivers/memory/stm32_omm.c index 84eb23c824f5..3599683ab04a 100644 --- a/drivers/memory/stm32_omm.c +++ b/drivers/memory/stm32_omm.c @@ -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); diff --git a/drivers/memory/tegra/tegra264.c b/drivers/memory/tegra/tegra264.c index 790349295dcc..57e6395861ba 100644 --- a/drivers/memory/tegra/tegra264.c +++ b/drivers/memory/tegra/tegra264.c @@ -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)