1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright 2018 NXP 4 */ 5 6 #include <common.h> 7 #include <linux/libfdt.h> 8 #include <fdt_support.h> 9 10 #include <asm/io.h> 11 #include <asm/processor.h> 12 #include <asm/arch-fsl-layerscape/fsl_icid.h> 13 #include <fsl_fman.h> 14 15 static void set_icid(struct icid_id_table *tbl, int size) 16 { 17 int i; 18 19 for (i = 0; i < size; i++) 20 out_be32((u32 *)(tbl[i].reg_addr), tbl[i].reg); 21 } 22 23 #ifdef CONFIG_SYS_DPAA_FMAN 24 void set_fman_icids(struct fman_icid_id_table *tbl, int size) 25 { 26 int i; 27 ccsr_fman_t *fm = (void *)CONFIG_SYS_FSL_FM1_ADDR; 28 29 for (i = 0; i < size; i++) { 30 out_be32(&fm->fm_bmi_common.fmbm_ppid[tbl[i].port_id - 1], 31 tbl[i].icid); 32 } 33 } 34 #endif 35 36 void set_icids(void) 37 { 38 /* setup general icid offsets */ 39 set_icid(icid_tbl, icid_tbl_sz); 40 41 #ifdef CONFIG_SYS_DPAA_FMAN 42 set_fman_icids(fman_icid_tbl, fman_icid_tbl_sz); 43 #endif 44 } 45 46 int fdt_set_iommu_prop(void *blob, int off, int smmu_ph, u32 *ids, int num_ids) 47 { 48 int i, ret; 49 u32 prop[8]; 50 51 /* 52 * Note: The "iommus" property definition mentions Stream IDs while 53 * this code handles ICIDs. The current implementation assumes that 54 * ICIDs and Stream IDs are equal. 55 */ 56 for (i = 0; i < num_ids; i++) { 57 prop[i * 2] = cpu_to_fdt32(smmu_ph); 58 prop[i * 2 + 1] = cpu_to_fdt32(ids[i]); 59 } 60 ret = fdt_setprop(blob, off, "iommus", 61 prop, sizeof(u32) * num_ids * 2); 62 if (ret) { 63 printf("WARNING unable to set iommus: %s\n", fdt_strerror(ret)); 64 return ret; 65 } 66 67 return 0; 68 } 69 70 int fdt_fixup_icid_tbl(void *blob, int smmu_ph, 71 struct icid_id_table *tbl, int size) 72 { 73 int i, err, off; 74 75 for (i = 0; i < size; i++) { 76 if (!tbl[i].compat) 77 continue; 78 79 off = fdt_node_offset_by_compat_reg(blob, 80 tbl[i].compat, 81 tbl[i].compat_addr); 82 if (off > 0) { 83 err = fdt_set_iommu_prop(blob, off, smmu_ph, 84 &tbl[i].id, 1); 85 if (err) 86 return err; 87 } else { 88 printf("WARNING could not find node %s: %s.\n", 89 tbl[i].compat, fdt_strerror(off)); 90 } 91 } 92 93 return 0; 94 } 95 96 #ifdef CONFIG_SYS_DPAA_FMAN 97 int get_fman_port_icid(int port_id, struct fman_icid_id_table *tbl, 98 const int size) 99 { 100 int i; 101 102 for (i = 0; i < size; i++) { 103 if (tbl[i].port_id == port_id) 104 return tbl[i].icid; 105 } 106 107 return -1; 108 } 109 110 void fdt_fixup_fman_port_icid_by_compat(void *blob, int smmu_ph, 111 const char *compat) 112 { 113 int noff, len, icid; 114 const u32 *prop; 115 116 noff = fdt_node_offset_by_compatible(blob, -1, compat); 117 while (noff > 0) { 118 prop = fdt_getprop(blob, noff, "cell-index", &len); 119 if (!prop) { 120 printf("WARNING missing cell-index for fman port\n"); 121 continue; 122 } 123 if (len != 4) { 124 printf("WARNING bad cell-index size for fman port\n"); 125 continue; 126 } 127 128 icid = get_fman_port_icid(fdt32_to_cpu(*prop), 129 fman_icid_tbl, fman_icid_tbl_sz); 130 if (icid < 0) { 131 printf("WARNING unknown ICID for fman port %d\n", 132 *prop); 133 continue; 134 } 135 136 fdt_set_iommu_prop(blob, noff, smmu_ph, (u32 *)&icid, 1); 137 138 noff = fdt_node_offset_by_compatible(blob, noff, compat); 139 } 140 } 141 142 void fdt_fixup_fman_icids(void *blob, int smmu_ph) 143 { 144 static const char * const compats[] = { 145 "fsl,fman-v3-port-oh", 146 "fsl,fman-v3-port-rx", 147 "fsl,fman-v3-port-tx", 148 }; 149 int i; 150 151 for (i = 0; i < ARRAY_SIZE(compats); i++) 152 fdt_fixup_fman_port_icid_by_compat(blob, smmu_ph, compats[i]); 153 } 154 #endif 155 156 int fdt_get_smmu_phandle(void *blob) 157 { 158 int noff, smmu_ph; 159 160 noff = fdt_node_offset_by_compatible(blob, -1, "arm,mmu-500"); 161 if (noff < 0) { 162 printf("WARNING failed to get smmu node: %s\n", 163 fdt_strerror(noff)); 164 return noff; 165 } 166 167 smmu_ph = fdt_get_phandle(blob, noff); 168 if (!smmu_ph) { 169 smmu_ph = fdt_create_phandle(blob, noff); 170 if (!smmu_ph) { 171 printf("WARNING failed to get smmu phandle\n"); 172 return -1; 173 } 174 } 175 176 return smmu_ph; 177 } 178 179 void fdt_fixup_icid(void *blob) 180 { 181 int smmu_ph; 182 183 smmu_ph = fdt_get_smmu_phandle(blob); 184 if (smmu_ph < 0) 185 return; 186 187 fdt_fixup_icid_tbl(blob, smmu_ph, icid_tbl, icid_tbl_sz); 188 189 #ifdef CONFIG_SYS_DPAA_FMAN 190 fdt_fixup_fman_icids(blob, smmu_ph); 191 #endif 192 } 193