#define NR_V8PE_OUT_SIGS       3
 #define NR_V8ETM_INOUT_SIGS    4
 
+/* CTI device tree trigger connection node keyword */
+#define CTI_DT_CONNS           "trig-conns"
+
 /* CTI device tree connection property keywords */
 #define CTI_DT_V8ARCH_COMPAT   "arm,coresight-cti-v8-arch"
 #define CTI_DT_CSDEV_ASSOC     "arm,cs-dev-assoc"
+#define CTI_DT_TRIGIN_SIGS     "arm,trig-in-sigs"
+#define CTI_DT_TRIGOUT_SIGS    "arm,trig-out-sigs"
+#define CTI_DT_TRIGIN_TYPES    "arm,trig-in-types"
+#define CTI_DT_TRIGOUT_TYPES   "arm,trig-out-types"
+#define CTI_DT_FILTER_OUT_SIGS "arm,trig-filters"
+#define CTI_DT_CONN_NAME       "arm,trig-conn-name"
+#define CTI_DT_CTM_ID          "arm,cti-ctm-id"
 
 #ifdef CONFIG_OF
 /*
        return name;
 }
 
+static bool cti_plat_node_name_eq(struct fwnode_handle *fwnode,
+                                 const char *name)
+{
+       if (is_of_node(fwnode))
+               return of_node_name_eq(to_of_node(fwnode), name);
+       return false;
+}
+
 static int cti_plat_create_v8_etm_connection(struct device *dev,
                                             struct cti_drvdata *drvdata)
 {
        return 0;
 }
 
+static int cti_plat_count_sig_elements(const struct fwnode_handle *fwnode,
+                                      const char *name)
+{
+       int nr_elem = fwnode_property_count_u32(fwnode, name);
+
+       return (nr_elem < 0 ? 0 : nr_elem);
+}
+
+static int cti_plat_read_trig_group(struct cti_trig_grp *tgrp,
+                                   const struct fwnode_handle *fwnode,
+                                   const char *grp_name)
+{
+       int idx, err = 0;
+       u32 *values;
+
+       if (!tgrp->nr_sigs)
+               return 0;
+
+       values = kcalloc(tgrp->nr_sigs, sizeof(u32), GFP_KERNEL);
+       if (!values)
+               return -ENOMEM;
+
+       err = fwnode_property_read_u32_array(fwnode, grp_name,
+                                            values, tgrp->nr_sigs);
+
+       if (!err) {
+               /* set the signal usage mask */
+               for (idx = 0; idx < tgrp->nr_sigs; idx++)
+                       tgrp->used_mask |= BIT(values[idx]);
+       }
+
+       kfree(values);
+       return err;
+}
+
+static int cti_plat_read_trig_types(struct cti_trig_grp *tgrp,
+                                   const struct fwnode_handle *fwnode,
+                                   const char *type_name)
+{
+       int items, err = 0, nr_sigs;
+       u32 *values = NULL, i;
+
+       /* allocate an array according to number of signals in connection */
+       nr_sigs = tgrp->nr_sigs;
+       if (!nr_sigs)
+               return 0;
+
+       /* see if any types have been included in the device description */
+       items = cti_plat_count_sig_elements(fwnode, type_name);
+       if (items > nr_sigs)
+               return -EINVAL;
+
+       /* need an array to store the values iff there are any */
+       if (items) {
+               values = kcalloc(items, sizeof(u32), GFP_KERNEL);
+               if (!values)
+                       return -ENOMEM;
+
+               err = fwnode_property_read_u32_array(fwnode, type_name,
+                                                    values, items);
+               if (err)
+                       goto read_trig_types_out;
+       }
+
+       /*
+        * Match type id to signal index, 1st type to 1st index etc.
+        * If fewer types than signals default remainder to GEN_IO.
+        */
+       for (i = 0; i < nr_sigs; i++) {
+               if (i < items) {
+                       tgrp->sig_types[i] =
+                               values[i] < CTI_TRIG_MAX ? values[i] : GEN_IO;
+               } else {
+                       tgrp->sig_types[i] = GEN_IO;
+               }
+       }
+
+read_trig_types_out:
+       kfree(values);
+       return err;
+}
+
+static int cti_plat_process_filter_sigs(struct cti_drvdata *drvdata,
+                                       const struct fwnode_handle *fwnode)
+{
+       struct cti_trig_grp *tg = NULL;
+       int err = 0, nr_filter_sigs;
+
+       nr_filter_sigs = cti_plat_count_sig_elements(fwnode,
+                                                    CTI_DT_FILTER_OUT_SIGS);
+       if (nr_filter_sigs == 0)
+               return 0;
+
+       if (nr_filter_sigs > drvdata->config.nr_trig_max)
+               return -EINVAL;
+
+       tg = kzalloc(sizeof(*tg), GFP_KERNEL);
+       if (!tg)
+               return -ENOMEM;
+
+       err = cti_plat_read_trig_group(tg, fwnode, CTI_DT_FILTER_OUT_SIGS);
+       if (!err)
+               drvdata->config.trig_out_filter |= tg->used_mask;
+
+       kfree(tg);
+       return err;
+}
+
+static int cti_plat_create_connection(struct device *dev,
+                                     struct cti_drvdata *drvdata,
+                                     struct fwnode_handle *fwnode)
+{
+       struct cti_trig_con *tc = NULL;
+       int cpuid = -1, err = 0;
+       struct fwnode_handle *cs_fwnode = NULL;
+       struct coresight_device *csdev = NULL;
+       const char *assoc_name = "unknown";
+       char cpu_name_str[16];
+       int nr_sigs_in, nr_sigs_out;
+
+       /* look to see how many in and out signals we have */
+       nr_sigs_in = cti_plat_count_sig_elements(fwnode, CTI_DT_TRIGIN_SIGS);
+       nr_sigs_out = cti_plat_count_sig_elements(fwnode, CTI_DT_TRIGOUT_SIGS);
+
+       if ((nr_sigs_in > drvdata->config.nr_trig_max) ||
+           (nr_sigs_out > drvdata->config.nr_trig_max))
+               return -EINVAL;
+
+       tc = cti_allocate_trig_con(dev, nr_sigs_in, nr_sigs_out);
+       if (!tc)
+               return -ENOMEM;
+
+       /* look for the signals properties. */
+       err = cti_plat_read_trig_group(tc->con_in, fwnode,
+                                      CTI_DT_TRIGIN_SIGS);
+       if (err)
+               goto create_con_err;
+
+       err = cti_plat_read_trig_types(tc->con_in, fwnode,
+                                      CTI_DT_TRIGIN_TYPES);
+       if (err)
+               goto create_con_err;
+
+       err = cti_plat_read_trig_group(tc->con_out, fwnode,
+                                      CTI_DT_TRIGOUT_SIGS);
+       if (err)
+               goto create_con_err;
+
+       err = cti_plat_read_trig_types(tc->con_out, fwnode,
+                                      CTI_DT_TRIGOUT_TYPES);
+       if (err)
+               goto create_con_err;
+
+       err = cti_plat_process_filter_sigs(drvdata, fwnode);
+       if (err)
+               goto create_con_err;
+
+       /* read the connection name if set - may be overridden by later */
+       fwnode_property_read_string(fwnode, CTI_DT_CONN_NAME, &assoc_name);
+
+       /* associated cpu ? */
+       cpuid = cti_plat_get_cpu_at_node(fwnode);
+       if (cpuid >= 0) {
+               drvdata->ctidev.cpu = cpuid;
+               scnprintf(cpu_name_str, sizeof(cpu_name_str), "cpu%d", cpuid);
+               assoc_name = cpu_name_str;
+       } else {
+               /* associated device ? */
+               cs_fwnode = fwnode_find_reference(fwnode,
+                                                 CTI_DT_CSDEV_ASSOC, 0);
+               if (!IS_ERR_OR_NULL(cs_fwnode)) {
+                       assoc_name = cti_plat_get_csdev_or_node_name(cs_fwnode,
+                                                                    &csdev);
+                       fwnode_handle_put(cs_fwnode);
+               }
+       }
+       /* set up a connection */
+       err = cti_add_connection_entry(dev, drvdata, tc, csdev, assoc_name);
+
+create_con_err:
+       return err;
+}
+
+static int cti_plat_create_impdef_connections(struct device *dev,
+                                             struct cti_drvdata *drvdata)
+{
+       int rc = 0;
+       struct fwnode_handle *fwnode = dev_fwnode(dev);
+       struct fwnode_handle *child = NULL;
+
+       if (IS_ERR_OR_NULL(fwnode))
+               return -EINVAL;
+
+       fwnode_for_each_child_node(fwnode, child) {
+               if (cti_plat_node_name_eq(child, CTI_DT_CONNS))
+                       rc = cti_plat_create_connection(dev, drvdata,
+                                                       child);
+               if (rc != 0)
+                       break;
+       }
+       fwnode_handle_put(child);
+
+       return rc;
+}
+
 /* get the hardware configuration & connection data. */
 int cti_plat_get_hw_data(struct device *dev,
                         struct cti_drvdata *drvdata)
        int rc = 0;
        struct cti_device *cti_dev = &drvdata->ctidev;
 
+       /* get any CTM ID - defaults to 0 */
+       device_property_read_u32(dev, CTI_DT_CTM_ID, &cti_dev->ctm_id);
+
        /* check for a v8 architectural CTI device */
-       if (cti_plat_check_v8_arch_compatible(dev)) {
+       if (cti_plat_check_v8_arch_compatible(dev))
                rc = cti_plat_create_v8_connections(dev, drvdata);
-               if (rc)
-                       return rc;
-       }
+       else
+               rc = cti_plat_create_impdef_connections(dev, drvdata);
+       if (rc)
+               return rc;
 
        /* if no connections, just add a single default based on max IN-OUT */
        if (cti_dev->nr_trig_con == 0)