// SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2018 NXP */ #include #include #include #include #include #include #include static void set_icid(struct icid_id_table *tbl, int size) { int i; for (i = 0; i < size; i++) if (tbl[i].le) out_le32((u32 *)(tbl[i].reg_addr), tbl[i].reg); else out_be32((u32 *)(tbl[i].reg_addr), tbl[i].reg); } #ifdef CONFIG_SYS_DPAA_FMAN void set_fman_icids(struct fman_icid_id_table *tbl, int size) { int i; ccsr_fman_t *fm = (void *)CFG_SYS_FSL_FM1_ADDR; for (i = 0; i < size; i++) { out_be32(&fm->fm_bmi_common.fmbm_ppid[tbl[i].port_id - 1], tbl[i].icid); } } #endif void set_icids(void) { /* setup general icid offsets */ set_icid(icid_tbl, icid_tbl_sz); #if defined(CONFIG_SYS_DPAA_FMAN) && !defined(CONFIG_SPL_BUILD) set_fman_icids(fman_icid_tbl, fman_icid_tbl_sz); #endif } #ifndef CONFIG_SPL_BUILD int fdt_set_iommu_prop(void *blob, int off, int smmu_ph, u32 *ids, int num_ids) { int i, ret; u32 prop[8]; /* * Note: The "iommus" property definition mentions Stream IDs while * this code handles ICIDs. The current implementation assumes that * ICIDs and Stream IDs are equal. */ for (i = 0; i < num_ids; i++) { prop[i * 2] = cpu_to_fdt32(smmu_ph); prop[i * 2 + 1] = cpu_to_fdt32(ids[i]); } ret = fdt_setprop(blob, off, "iommus", prop, sizeof(u32) * num_ids * 2); if (ret) { printf("WARNING unable to set iommus: %s\n", fdt_strerror(ret)); return ret; } return 0; } int fdt_fixup_icid_tbl(void *blob, int smmu_ph, struct icid_id_table *tbl, int size) { int i, err, off; for (i = 0; i < size; i++) { if (!tbl[i].compat) continue; off = fdt_node_offset_by_compat_reg(blob, tbl[i].compat, tbl[i].compat_addr); if (off > 0) { err = fdt_set_iommu_prop(blob, off, smmu_ph, &tbl[i].id, 1); if (err) return err; } else { printf("WARNING could not find node %s: %s.\n", tbl[i].compat, fdt_strerror(off)); } } return 0; } #ifdef CONFIG_SYS_DPAA_FMAN int get_fman_port_icid(int port_id, struct fman_icid_id_table *tbl, const int size) { int i; for (i = 0; i < size; i++) { if (tbl[i].port_id == port_id) return tbl[i].icid; } return -1; } void fdt_fixup_fman_port_icid_by_compat(void *blob, int smmu_ph, const char *compat) { int noff, len, icid; const u32 *prop; fdt_for_each_node_by_compatible(noff, blob, -1, compat) { prop = fdt_getprop(blob, noff, "cell-index", &len); if (!prop) { printf("WARNING missing cell-index for fman port\n"); continue; } if (len != 4) { printf("WARNING bad cell-index size for fman port\n"); continue; } icid = get_fman_port_icid(fdt32_to_cpu(*prop), fman_icid_tbl, fman_icid_tbl_sz); if (icid < 0) { printf("WARNING unknown ICID for fman port %d\n", *prop); continue; } fdt_set_iommu_prop(blob, noff, smmu_ph, (u32 *)&icid, 1); } } void fdt_fixup_fman_icids(void *blob, int smmu_ph) { static const char * const compats[] = { "fsl,fman-v3-port-oh", "fsl,fman-v3-port-rx", "fsl,fman-v3-port-tx", }; int i; for (i = 0; i < ARRAY_SIZE(compats); i++) fdt_fixup_fman_port_icid_by_compat(blob, smmu_ph, compats[i]); } #endif int fdt_get_smmu_phandle(void *blob) { int noff, smmu_ph; noff = fdt_node_offset_by_compatible(blob, -1, "arm,mmu-500"); if (noff < 0) { printf("WARNING failed to get smmu node: %s\n", fdt_strerror(noff)); return noff; } smmu_ph = fdt_get_phandle(blob, noff); if (!smmu_ph) { smmu_ph = fdt_create_phandle(blob, noff); if (!smmu_ph) { printf("WARNING failed to get smmu phandle\n"); return -1; } } return smmu_ph; } void fdt_fixup_icid(void *blob) { int smmu_ph; smmu_ph = fdt_get_smmu_phandle(blob); if (smmu_ph < 0) return; fdt_fixup_icid_tbl(blob, smmu_ph, icid_tbl, icid_tbl_sz); #ifdef CONFIG_SYS_DPAA_FMAN fdt_fixup_fman_icids(blob, smmu_ph); #endif } #endif