diff --git a/drivers/dpll/dpll_zl3073x.c b/drivers/dpll/dpll_zl3073x.c
index 07a547aaee0f1..c920904008e22 100644
--- a/drivers/dpll/dpll_zl3073x.c
+++ b/drivers/dpll/dpll_zl3073x.c
@@ -1246,6 +1246,50 @@ zl3073x_dpll_pin_info_package_label_set(struct zl3073x_dpll_pin *pin,
 	pin_info->props.package_label = pin_info->package_label;
 }
 
+/**
+ * zl3073x_dpll_check_frequency - verify frequency for given pin
+ * @pin: pointer to pin
+ * @freq: frequency to check
+ *
+ * The function checks the given frequency is valid for the device. For input
+ * pins it checks that the frequency can be factorized using supported base
+ * frequencies. For output pins it checks that the frequency divides connected
+ * synth frequency without remainder.
+ *
+ * Returns true if the frequency is valid or false if not.
+ */
+static bool
+zl3073x_dpll_check_frequency(struct zl3073x_dpll_pin *pin, u64 freq)
+{
+	if (zl3073x_dpll_is_input_pin(pin)) {
+		u16 base, mult;
+		int rc;
+
+		/* Check if the frequency can be factorized */
+		rc = zl3073x_dpll_input_ref_frequency_factorize(freq, &base,
+								&mult);
+		if (!rc)
+			return true;
+	} else {
+		struct zl3073x_dev *zldev = pin_to_dev(pin);
+		u64 synth_freq, rem;
+		u8 synth;
+
+		/* Get output pin synthesizer */
+		synth = zl3073x_dpll_pin_synth_get(pin);
+
+		/* Get synth frequency */
+		synth_freq = zl3073x_synth_freq_get(zldev, synth);
+
+		/* Check the frequency divides synth frequency */
+		div64_u64_rem(synth_freq, freq, &rem);
+		if (!rem)
+			return true;
+	}
+
+	return false;
+}
+
 /**
  * zl3073x_dpll_pin_info_get - get pin info
  * @pin: pin whose info is returned
@@ -1253,7 +1297,8 @@ zl3073x_dpll_pin_info_package_label_set(struct zl3073x_dpll_pin *pin,
  * The function looks for firmware node for the given pin if it is provided
  * by the system firmware (DT or ACPI), allocates pin info structure,
  * generates package label string according pin type and its order number
- * and optionally fetches board label from the firmware node if it exists.
+ * and optionally fetches board label and supported frequencies from
+ * the firmware node if they exist.
  *
  * Returns pointer to allocated pin info structure that has to be freed
  * by @zl3073x_dpll_pin_info_put by the caller and in case of error
@@ -1264,7 +1309,10 @@ zl3073x_dpll_pin_info_get(struct zl3073x_dpll_pin *pin)
 {
 	struct zl3073x_dev *zldev = pin_to_dev(pin);
 	struct zl3073x_dpll_pin_info *pin_info;
+	struct dpll_pin_frequency *ranges;
+	int i, j, num_freqs, rc;
 	const char *pin_type;
+	u64 *freqs;
 
 	/* Allocate pin info structure */
 	pin_info = kzalloc(sizeof(*pin_info), GFP_KERNEL);
@@ -1315,7 +1363,67 @@ zl3073x_dpll_pin_info_get(struct zl3073x_dpll_pin *pin)
 				 pin_type);
 	}
 
+	/* Read supported frequencies property if it is specified */
+	num_freqs = fwnode_property_count_u64(pin_info->fwnode,
+					      "supported-frequencies");
+	if (num_freqs <= 0)
+		/* Return if the property does not exist or number is 0 */
+		return pin_info;
+
+	/* The firmware node specifies list of supported frequencies while
+	 * DPLL core pin properties requires list of frequency ranges.
+	 * So read the frequency list into temporary array.
+	 */
+	freqs = kcalloc(num_freqs, sizeof(*freqs), GFP_KERNEL);
+	if (!freqs) {
+		rc = -ENOMEM;
+		goto err_alloc_freqs;
+	}
+
+	/* Read frequencies list from firmware node */
+	fwnode_property_read_u64_array(pin_info->fwnode,
+				       "supported-frequencies", freqs,
+				       num_freqs);
+
+	/* Allocate frequency ranges list and fill it */
+	ranges = kcalloc(num_freqs, sizeof(*ranges), GFP_KERNEL);
+	if (!ranges) {
+		rc = -ENOMEM;
+		goto err_alloc_ranges;
+	}
+
+	/* Convert list of frequencies to list of frequency ranges but
+	 * filter-out frequencies that are not representable by device
+	 */
+	for (i = 0, j = 0; i < num_freqs; i++) {
+		struct dpll_pin_frequency freq = DPLL_PIN_FREQUENCY(freqs[i]);
+
+		if (zl3073x_dpll_check_frequency(pin, freqs[i])) {
+			ranges[j] = freq;
+			j++;
+		} else {
+			dev_warn(zldev->dev,
+				 "Unsupported frequency %llu Hz in firmware node\n",
+				 freqs[i]);
+		}
+	}
+
+	/* Save number of freq ranges and pointer to them into pin properties */
+	pin_info->props.freq_supported = ranges;
+	pin_info->props.freq_supported_num = j;
+
+	/* Free temporary array */
+	kfree(freqs);
+
 	return pin_info;
+
+err_alloc_ranges:
+	kfree(freqs);
+err_alloc_freqs:
+	fwnode_handle_put(pin_info->fwnode);
+	kfree(pin_info);
+
+	return ERR_PTR(rc);
 }
 
 /**
@@ -1327,6 +1435,9 @@ zl3073x_dpll_pin_info_get(struct zl3073x_dpll_pin *pin)
 static void
 zl3073x_dpll_pin_info_put(struct zl3073x_dpll_pin_info *pin_info)
 {
+	/* Free supported frequency ranges list if it is present */
+	kfree(pin_info->props.freq_supported);
+
 	/* Put firmware handle if it is present */
 	if (pin_info->fwnode)
 		fwnode_handle_put(pin_info->fwnode);
