diff --git a/arch/arm/mach-at91/include/mach/sama5_sfr.h b/arch/arm/mach-at91/include/mach/sama5_sfr.h
index b805a2c93495e80e2a20a3a262dbc64d6471b6ba..965631aad76f32534855fbf06dcb255e99874846 100644
--- a/arch/arm/mach-at91/include/mach/sama5_sfr.h
+++ b/arch/arm/mach-at91/include/mach/sama5_sfr.h
@@ -28,6 +28,9 @@ struct atmel_sfr {
 	u32 l2cc_hramc;	/* 0x58 */
 };
 
+/* Register Mapping*/
+#define AT91_SFR_UTMICKTRIM	0x30	/* UTMI Clock Trimming Register */
+
 /* Bit field in DDRCFG */
 #define ATMEL_SFR_DDRCFG_FDQIEN		0x00010000
 #define ATMEL_SFR_DDRCFG_FDQSIEN	0x00020000
@@ -56,6 +59,8 @@ struct atmel_sfr {
 #define AT91_SFR_EBICFG_SCH1_OFF		(0x0 << 12)
 #define AT91_SFR_EBICFG_SCH1_ON			(0x1 << 12)
 
+#define AT91_UTMICKTRIM_FREQ		GENMASK(1, 0)
+
 /* Bit field in AICREDIR */
 #define ATMEL_SFR_AICREDIR_NSAIC	0x00000001
 
diff --git a/drivers/clk/at91/Kconfig b/drivers/clk/at91/Kconfig
index 904ed48e51e0f071629afb9b41042d7765891cbb..c6c57618c149a2fc514d687c64ea76805688eb30 100644
--- a/drivers/clk/at91/Kconfig
+++ b/drivers/clk/at91/Kconfig
@@ -14,7 +14,11 @@ config CLK_AT91
 
 config AT91_UTMI
 	bool "Support UTMI PLL Clock"
-	depends on CLK_AT91
+	depends on CLK_AT91 && SPL_DM
+	select REGMAP
+	select SPL_REGMAP
+	select SYSCON
+	select SPL_SYSCON
 	help
 	  This option is used to enable the AT91 UTMI PLL clock
 	  driver. It is the clock provider of USB, and UPLLCK is the
diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c
index af5362da4205a7f42088319edf2917895501b8af..875bf293f9cdd637ccf47955a3733a4592a0f8d0 100644
--- a/drivers/clk/at91/clk-utmi.c
+++ b/drivers/clk/at91/clk-utmi.c
@@ -8,23 +8,80 @@
 #include <common.h>
 #include <clk-uclass.h>
 #include <dm.h>
+#include <syscon.h>
 #include <linux/io.h>
 #include <mach/at91_pmc.h>
+#include <mach/sama5_sfr.h>
 #include "pmc.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
-#define UTMI_FIXED_MUL		40
+/*
+ * The purpose of this clock is to generate a 480 MHz signal. A different
+ * rate can't be configured.
+ */
+#define UTMI_RATE	480000000
 
 static int utmi_clk_enable(struct clk *clk)
 {
 	struct pmc_platdata *plat = dev_get_platdata(clk->dev);
 	struct at91_pmc *pmc = plat->reg_base;
+	struct clk clk_dev;
+	ulong clk_rate;
+	u32 utmi_ref_clk_freq;
 	u32 tmp;
+	int err;
 
 	if (readl(&pmc->sr) & AT91_PMC_LOCKU)
 		return 0;
 
+	/*
+	 * If mainck rate is different from 12 MHz, we have to configure the
+	 * FREQ field of the SFR_UTMICKTRIM register to generate properly
+	 * the utmi clock.
+	 */
+	err = clk_get_by_index(clk->dev, 0, &clk_dev);
+	if (err)
+		return -EINVAL;
+
+	clk_rate = clk_get_rate(&clk_dev);
+	switch (clk_rate) {
+	case 12000000:
+		utmi_ref_clk_freq = 0;
+		break;
+	case 16000000:
+		utmi_ref_clk_freq = 1;
+		break;
+	case 24000000:
+		utmi_ref_clk_freq = 2;
+		break;
+	/*
+	 * Not supported on SAMA5D2 but it's not an issue since MAINCK
+	 * maximum value is 24 MHz.
+	 */
+	case 48000000:
+		utmi_ref_clk_freq = 3;
+		break;
+	default:
+		printf("UTMICK: unsupported mainck rate\n");
+		return -EINVAL;
+	}
+
+	if (plat->regmap_sfr) {
+		err = regmap_read(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, &tmp);
+		if (err)
+			return -EINVAL;
+
+		tmp &= ~AT91_UTMICKTRIM_FREQ;
+		tmp |= utmi_ref_clk_freq;
+		err = regmap_write(plat->regmap_sfr, AT91_SFR_UTMICKTRIM, tmp);
+		if (err)
+			return -EINVAL;
+	} else if (utmi_ref_clk_freq) {
+		printf("UTMICK: sfr node required\n");
+		return -EINVAL;
+	}
+
 	tmp = readl(&pmc->uckr);
 	tmp |= AT91_PMC_UPLLEN |
 	       AT91_PMC_UPLLCOUNT |
@@ -39,7 +96,8 @@ static int utmi_clk_enable(struct clk *clk)
 
 static ulong utmi_clk_get_rate(struct clk *clk)
 {
-	return gd->arch.main_clk_rate_hz * UTMI_FIXED_MUL;
+	/* UTMI clk rate is fixed. */
+	return UTMI_RATE;
 }
 
 static struct clk_ops utmi_clk_ops = {
@@ -47,6 +105,20 @@ static struct clk_ops utmi_clk_ops = {
 	.get_rate = utmi_clk_get_rate,
 };
 
+static int utmi_clk_ofdata_to_platdata(struct udevice *dev)
+{
+	struct pmc_platdata *plat = dev_get_platdata(dev);
+	struct udevice *syscon;
+
+	uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
+				     "regmap-sfr", &syscon);
+
+	if (syscon)
+		plat->regmap_sfr = syscon_get_regmap(syscon);
+
+	return 0;
+}
+
 static int utmi_clk_probe(struct udevice *dev)
 {
 	return at91_pmc_core_probe(dev);
@@ -62,6 +134,7 @@ U_BOOT_DRIVER(at91sam9x5_utmi_clk) = {
 	.id = UCLASS_CLK,
 	.of_match = utmi_clk_match,
 	.probe = utmi_clk_probe,
+	.ofdata_to_platdata = utmi_clk_ofdata_to_platdata,
 	.platdata_auto_alloc_size = sizeof(struct pmc_platdata),
 	.ops = &utmi_clk_ops,
 };
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
index bd3caba48d1d9bc0b92bb55e286f1daf771e1919..5abda764a221b6eca86503b527f33383524fc6b6 100644
--- a/drivers/clk/at91/pmc.h
+++ b/drivers/clk/at91/pmc.h
@@ -8,8 +8,11 @@
 #ifndef __AT91_PMC_H__
 #define __AT91_PMC_H__
 
+#include <regmap.h>
+
 struct pmc_platdata {
 	struct at91_pmc *reg_base;
+	struct regmap *regmap_sfr;
 };
 
 int at91_pmc_core_probe(struct udevice *dev);