From nobody Sun Dec 22 07:56:03 2024 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4B6F722836C; Fri, 20 Dec 2024 21:09:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=68.232.154.123 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734728956; cv=none; b=KnOzk5ZfN9bwq5P1Ym/CTKgezUXWpeQuiBbVLJzixZOgBDLmbvUChhBcbIii26GB+UcEgof6vVgoxhkRVHx1mCOvlqbj1fa4aYkDCGC7p0Pz07i5U9Fd8uhegvF38ov6cmMMo4NqDNmIJcA/6cC4+4w2wBDSXf/y6WpsoPo5/Ps= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734728956; c=relaxed/simple; bh=3vrXVOG2sgNM5y7IXiO8+b0m+fY9n+dRbOJyFmGg+qc=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Kg5MxvwwjigJZXJAXqXFL4tvDqyeF+g1RRa3QxVuKH8yjlqPIBecEZTRKN/RF+YZc/RPBvvo4Z8dq4qcjHaO4advXDUIkR9x39baTul8qs+BqbWKY6427w2wre3jSKUOQqmSFNgoARCLUmECcrtCZtaGQu4Ke9AqLnUEe6f+jqs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com; spf=pass smtp.mailfrom=microchip.com; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b=FgBK70/J; arc=none smtp.client-ip=68.232.154.123 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=microchip.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="FgBK70/J" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1734728953; x=1766264953; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=3vrXVOG2sgNM5y7IXiO8+b0m+fY9n+dRbOJyFmGg+qc=; b=FgBK70/J9O2pqhcieUm99l3CE6ib7xpAz6AuPw9GL2KNHpZsunZ3BfbS 0cEJ0NiQpDe5GrtMfdfrei4J0MYVe9aW6csGyLIdT7H3mcTL0at4iAvIK cwm6dIR6GOV2ytwwD2yLe64OQz8Wl0WRKn0Vq6cudbQWEF0x1X+d/Eirk looZ02g4wRaZUjlWwTTyX+3ZZwy3qiV9QMdvzZWgL0ScYbjsyC+ahQrch p0Dt9CdbM09WC7KiPf4eGCBwcWPckOfE5GogWVRUxiuQSfxcSWO7HeHyT bXfDcdMq3m4BU+8BOLCoaRbTSZBy3Y42uXoZ5hi2q16UCfRNK/76TgtF1 Q==; X-CSE-ConnectionGUID: 6Xn2bQedQHqhtDmL7ky2MQ== X-CSE-MsgGUID: l8zZfGI9QmuR4zHj72NppA== X-IronPort-AV: E=Sophos;i="6.12,251,1728975600"; d="scan'208";a="203274646" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa6.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 20 Dec 2024 14:09:09 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Fri, 20 Dec 2024 14:08:43 -0700 Received: from ryan-Precision-3630-Tower.microchip.com (10.10.85.11) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server id 15.1.2507.35 via Frontend Transport; Fri, 20 Dec 2024 14:08:43 -0700 From: To: , , , , , , , , CC: , , , , , , , , , , , , Ryan Wanner Subject: [PATCH v4 08/13] clk: at91: sama7d65: add sama7d65 pmc driver Date: Fri, 20 Dec 2024 14:07:09 -0700 Message-ID: <549fa8590fe9b4380e413f8eed87392f28754395.1734723585.git.Ryan.Wanner@microchip.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Ryan Wanner Add clock support for SAMA7D65 SoC. Increase maximum number of valid master clocks. The PMC for the SAMA7D65 requires 9 master clocks. Increase maximum amount of PLLs to 9 to support SAMA7D65 SoC PLL requirements. Signed-off-by: Ryan Wanner Reviewed-by: Claudiu Beznea --- drivers/clk/at91/Makefile | 1 + drivers/clk/at91/clk-master.c | 2 +- drivers/clk/at91/clk-sam9x60-pll.c | 2 +- drivers/clk/at91/pmc.c | 1 + drivers/clk/at91/sama7d65.c | 1375 ++++++++++++++++++++++++++++ 5 files changed, 1379 insertions(+), 2 deletions(-) create mode 100644 drivers/clk/at91/sama7d65.c diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 8e3684ba2c74..5e638eb15aba 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -25,3 +25,4 @@ obj-$(CONFIG_SOC_SAMA5D3) +=3D sama5d3.o dt-compat.o obj-$(CONFIG_SOC_SAMA5D4) +=3D sama5d4.o dt-compat.o obj-$(CONFIG_SOC_SAMA5D2) +=3D sama5d2.o dt-compat.o obj-$(CONFIG_SOC_SAMA7G5) +=3D sama7g5.o +obj-$(CONFIG_SOC_SAMA7D65) +=3D sama7d65.o diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c index 15c46489ba85..7a544e429d34 100644 --- a/drivers/clk/at91/clk-master.c +++ b/drivers/clk/at91/clk-master.c @@ -20,7 +20,7 @@ =20 #define PMC_MCR_CSS_SHIFT (16) =20 -#define MASTER_MAX_ID 4 +#define MASTER_MAX_ID 9 =20 #define to_clk_master(hw) container_of(hw, struct clk_master, hw) =20 diff --git a/drivers/clk/at91/clk-sam9x60-pll.c b/drivers/clk/at91/clk-sam9= x60-pll.c index fda041102224..cefd9948e103 100644 --- a/drivers/clk/at91/clk-sam9x60-pll.c +++ b/drivers/clk/at91/clk-sam9x60-pll.c @@ -23,7 +23,7 @@ #define UPLL_DIV 2 #define PLL_MUL_MAX (FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, UINT_MAX) + 1) =20 -#define PLL_MAX_ID 7 +#define PLL_MAX_ID 9 =20 struct sam9x60_pll_core { struct regmap *regmap; diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c index 5aa9c1f1c886..acf780a81589 100644 --- a/drivers/clk/at91/pmc.c +++ b/drivers/clk/at91/pmc.c @@ -151,6 +151,7 @@ static struct syscore_ops pmc_syscore_ops =3D { static const struct of_device_id pmc_dt_ids[] =3D { { .compatible =3D "atmel,sama5d2-pmc" }, { .compatible =3D "microchip,sama7g5-pmc", }, + { .compatible =3D "microchip,sama7d65-pmc", }, { /* sentinel */ } }; =20 diff --git a/drivers/clk/at91/sama7d65.c b/drivers/clk/at91/sama7d65.c new file mode 100644 index 000000000000..917958eabd3a --- /dev/null +++ b/drivers/clk/at91/sama7d65.c @@ -0,0 +1,1375 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * SAMA7D65 PMC code. + * + * Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries + * + * Author: Ryan Wanner + */ +#include +#include +#include +#include + +#include + +#include "pmc.h" + +static DEFINE_SPINLOCK(pmc_pll_lock); +static DEFINE_SPINLOCK(pmc_mck0_lock); +static DEFINE_SPINLOCK(pmc_mckX_lock); + +#define PMC_INDEX_MAX 25 + +/* + * PLL clocks identifiers + * @PLL_ID_CPU: CPU PLL identifier + * @PLL_ID_SYS: System PLL identifier + * @PLL_ID_DDR: DDR PLL identifier + * @PLL_ID_GPU: Graphics subsystem PLL identifier + * @PLL_ID_BAUD: Baud PLL identifier + * @PLL_ID_AUDIO: Audio PLL identifier + * @PLL_ID_ETH: Ethernet PLL identifier + * @PLL_ID_LVDS: LVDS PLL identifier + * @PLL_ID_USB: USB PLL identifier + */ +enum pll_ids { + PLL_ID_CPU, + PLL_ID_SYS, + PLL_ID_DDR, + PLL_ID_GPU, + PLL_ID_BAUD, + PLL_ID_AUDIO, + PLL_ID_ETH, + PLL_ID_LVDS, + PLL_ID_USB, + PLL_ID_MAX +}; + +/* + * PLL component identifier + * @PLL_COMPID_FRAC: Fractional PLL component identifier + * @PLL_COMPID_DIV0: 1st PLL divider component identifier + * @PLL_COMPID_DIV1: 2nd PLL divider component identifier + */ +enum pll_component_id { + PLL_COMPID_FRAC, + PLL_COMPID_DIV0, + PLL_COMPID_DIV1, + PLL_COMPID_MAX +}; + +/* + * PLL type identifiers + * @PLL_TYPE_FRAC: fractional PLL identifier + * @PLL_TYPE_DIV: divider PLL identifier + */ +enum pll_type { + PLL_TYPE_FRAC, + PLL_TYPE_DIV +}; + +/* Layout for fractional PLLs. */ +static const struct clk_pll_layout pll_layout_frac =3D { + .mul_mask =3D GENMASK(31, 24), + .frac_mask =3D GENMASK(21, 0), + .mul_shift =3D 24, + .frac_shift =3D 0, +}; + +/* Layout for DIVPMC dividers. */ +static const struct clk_pll_layout pll_layout_divpmc =3D { + .div_mask =3D GENMASK(7, 0), + .endiv_mask =3D BIT(29), + .div_shift =3D 0, + .endiv_shift =3D 29, +}; + +/* Layout for DIVIO dividers. */ +static const struct clk_pll_layout pll_layout_divio =3D { + .div_mask =3D GENMASK(19, 12), + .endiv_mask =3D BIT(30), + .div_shift =3D 12, + .endiv_shift =3D 30, +}; + +/* + * CPU PLL output range. + * Notice: The upper limit has been setup to 1000000002 due to hardware + * block which cannot output exactly 1GHz. + */ +static const struct clk_range cpu_pll_outputs[] =3D { + { .min =3D 2343750, .max =3D 1000000002 }, +}; + +/* PLL output range. */ +static const struct clk_range pll_outputs[] =3D { + { .min =3D 2343750, .max =3D 1200000000 }, +}; + +/* + * Min: fCOREPLLCK =3D 600 MHz, PMC_PLL_CTRL0.DIVPMC =3D 255 + * Max: fCOREPLLCK =3D 800 MHz, PMC_PLL_CTRL0.DIVPMC =3D 0 + */ +static const struct clk_range lvdspll_outputs[] =3D { + { .min =3D 16406250, .max =3D 800000000 }, +}; + +static const struct clk_range upll_outputs[] =3D { + { .min =3D 480000000, .max =3D 480000000 }, +}; + +/* Fractional PLL core output range. */ +static const struct clk_range core_outputs[] =3D { + { .min =3D 600000000, .max =3D 1200000000 }, +}; + +static const struct clk_range lvdspll_core_outputs[] =3D { + { .min =3D 600000000, .max =3D 1200000000 }, +}; + +static const struct clk_range upll_core_outputs[] =3D { + { .min =3D 600000000, .max =3D 1200000000 }, +}; + +/* CPU PLL characteristics. */ +static const struct clk_pll_characteristics cpu_pll_characteristics =3D { + .input =3D { .min =3D 12000000, .max =3D 50000000 }, + .num_output =3D ARRAY_SIZE(cpu_pll_outputs), + .output =3D cpu_pll_outputs, + .core_output =3D core_outputs, +}; + +/* PLL characteristics. */ +static const struct clk_pll_characteristics pll_characteristics =3D { + .input =3D { .min =3D 12000000, .max =3D 50000000 }, + .num_output =3D ARRAY_SIZE(pll_outputs), + .output =3D pll_outputs, + .core_output =3D core_outputs, +}; + +static const struct clk_pll_characteristics lvdspll_characteristics =3D { + .input =3D { .min =3D 12000000, .max =3D 50000000 }, + .num_output =3D ARRAY_SIZE(lvdspll_outputs), + .output =3D lvdspll_outputs, + .core_output =3D lvdspll_core_outputs, +}; + +static const struct clk_pll_characteristics upll_characteristics =3D { + .input =3D { .min =3D 20000000, .max =3D 50000000 }, + .num_output =3D ARRAY_SIZE(upll_outputs), + .output =3D upll_outputs, + .core_output =3D upll_core_outputs, + .upll =3D true, +}; + +/* + * SAMA7D65 PLL possible parents + * @SAMA7D65_PLL_PARENT_MAINCK: MAINCK is PLL a parent + * @SAMA7D65_PLL_PARENT_MAIN_XTAL: MAIN XTAL is a PLL parent + * @SAMA7D65_PLL_PARENT_FRACCK: Frac PLL is a PLL parent (for PLL dividers) + */ +enum sama7d65_pll_parent { + SAMA7D65_PLL_PARENT_MAINCK, + SAMA7D65_PLL_PARENT_MAIN_XTAL, + SAMA7D65_PLL_PARENT_FRACCK +}; + +/* + * PLL clocks description + * @n: clock name + * @l: clock layout + * @c: clock characteristics + * @hw: pointer to clk_hw + * @t: clock type + * @f: clock flags + * @p: clock parent + * @eid: export index in sama7d65->chws[] array + * @safe_div: intermediate divider need to be set on PRE_RATE_CHANGE + * notification + */ +static struct sama7d65_pll { + const char *n; + const struct clk_pll_layout *l; + const struct clk_pll_characteristics *c; + struct clk_hw *hw; + unsigned long f; + enum sama7d65_pll_parent p; + u8 t; + u8 eid; + u8 safe_div; +} sama7d65_plls[][PLL_COMPID_MAX] =3D { + [PLL_ID_CPU] =3D { + [PLL_COMPID_FRAC] =3D { + .n =3D "cpupll_fracck", + .p =3D SAMA7D65_PLL_PARENT_MAINCK, + .l =3D &pll_layout_frac, + .c =3D &cpu_pll_characteristics, + .t =3D PLL_TYPE_FRAC, + /* + * This feeds cpupll_divpmcck which feeds CPU. It should + * not be disabled. + */ + .f =3D CLK_IS_CRITICAL, + }, + + [PLL_COMPID_DIV0] =3D { + .n =3D "cpupll_divpmcck", + .p =3D SAMA7D65_PLL_PARENT_FRACCK, + .l =3D &pll_layout_divpmc, + .c =3D &cpu_pll_characteristics, + .t =3D PLL_TYPE_DIV, + /* This feeds CPU. It should not be disabled. */ + .f =3D CLK_IS_CRITICAL | CLK_SET_RATE_PARENT, + .eid =3D PMC_CPUPLL, + /* + * Safe div=3D15 should be safe even for switching b/w 1GHz and + * 90MHz (frac pll might go up to 1.2GHz). + */ + .safe_div =3D 15, + }, + }, + + [PLL_ID_SYS] =3D { + [PLL_COMPID_FRAC] =3D { + .n =3D "syspll_fracck", + .p =3D SAMA7D65_PLL_PARENT_MAINCK, + .l =3D &pll_layout_frac, + .c =3D &pll_characteristics, + .t =3D PLL_TYPE_FRAC, + /* + * This feeds syspll_divpmcck which may feed critical parts + * of the systems like timers. Therefore it should not be + * disabled. + */ + .f =3D CLK_IS_CRITICAL | CLK_SET_RATE_GATE, + }, + + [PLL_COMPID_DIV0] =3D { + .n =3D "syspll_divpmcck", + .p =3D SAMA7D65_PLL_PARENT_FRACCK, + .l =3D &pll_layout_divpmc, + .c =3D &pll_characteristics, + .t =3D PLL_TYPE_DIV, + /* + * This may feed critical parts of the systems like timers. + * Therefore it should not be disabled. + */ + .f =3D CLK_IS_CRITICAL | CLK_SET_RATE_GATE, + .eid =3D PMC_SYSPLL, + }, + }, + + [PLL_ID_DDR] =3D { + [PLL_COMPID_FRAC] =3D { + .n =3D "ddrpll_fracck", + .p =3D SAMA7D65_PLL_PARENT_MAINCK, + .l =3D &pll_layout_frac, + .c =3D &pll_characteristics, + .t =3D PLL_TYPE_FRAC, + /* + * This feeds ddrpll_divpmcck which feeds DDR. It should not + * be disabled. + */ + .f =3D CLK_IS_CRITICAL | CLK_SET_RATE_GATE, + }, + + [PLL_COMPID_DIV0] =3D { + .n =3D "ddrpll_divpmcck", + .p =3D SAMA7D65_PLL_PARENT_FRACCK, + .l =3D &pll_layout_divpmc, + .c =3D &pll_characteristics, + .t =3D PLL_TYPE_DIV, + /* This feeds DDR. It should not be disabled. */ + .f =3D CLK_IS_CRITICAL | CLK_SET_RATE_GATE, + }, + }, + + [PLL_ID_GPU] =3D { + [PLL_COMPID_FRAC] =3D { + .n =3D "gpupll_fracck", + .p =3D SAMA7D65_PLL_PARENT_MAINCK, + .l =3D &pll_layout_frac, + .c =3D &pll_characteristics, + .t =3D PLL_TYPE_FRAC, + .f =3D CLK_SET_RATE_GATE, + }, + + [PLL_COMPID_DIV0] =3D { + .n =3D "gpupll_divpmcck", + .p =3D SAMA7D65_PLL_PARENT_FRACCK, + .l =3D &pll_layout_divpmc, + .c =3D &pll_characteristics, + .t =3D PLL_TYPE_DIV, + .f =3D CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | + CLK_SET_RATE_PARENT, + }, + }, + + [PLL_ID_BAUD] =3D { + [PLL_COMPID_FRAC] =3D { + .n =3D "baudpll_fracck", + .p =3D SAMA7D65_PLL_PARENT_MAINCK, + .l =3D &pll_layout_frac, + .c =3D &pll_characteristics, + .t =3D PLL_TYPE_FRAC, + .f =3D CLK_SET_RATE_GATE, + }, + + [PLL_COMPID_DIV0] =3D { + .n =3D "baudpll_divpmcck", + .p =3D SAMA7D65_PLL_PARENT_FRACCK, + .l =3D &pll_layout_divpmc, + .c =3D &pll_characteristics, + .t =3D PLL_TYPE_DIV, + .f =3D CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | + CLK_SET_RATE_PARENT, + .eid =3D PMC_BAUDPLL, + }, + }, + + [PLL_ID_AUDIO] =3D { + [PLL_COMPID_FRAC] =3D { + .n =3D "audiopll_fracck", + .p =3D SAMA7D65_PLL_PARENT_MAIN_XTAL, + .l =3D &pll_layout_frac, + .c =3D &pll_characteristics, + .t =3D PLL_TYPE_FRAC, + .f =3D CLK_SET_RATE_GATE, + }, + + [PLL_COMPID_DIV0] =3D { + .n =3D "audiopll_divpmcck", + .p =3D SAMA7D65_PLL_PARENT_FRACCK, + .l =3D &pll_layout_divpmc, + .c =3D &pll_characteristics, + .t =3D PLL_TYPE_DIV, + .f =3D CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | + CLK_SET_RATE_PARENT, + .eid =3D PMC_AUDIOPMCPLL, + }, + + [PLL_COMPID_DIV1] =3D { + .n =3D "audiopll_diviock", + .p =3D SAMA7D65_PLL_PARENT_FRACCK, + .l =3D &pll_layout_divio, + .c =3D &pll_characteristics, + .t =3D PLL_TYPE_DIV, + .f =3D CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | + CLK_SET_RATE_PARENT, + .eid =3D PMC_AUDIOIOPLL, + }, + }, + + [PLL_ID_ETH] =3D { + [PLL_COMPID_FRAC] =3D { + .n =3D "ethpll_fracck", + .p =3D SAMA7D65_PLL_PARENT_MAIN_XTAL, + .l =3D &pll_layout_frac, + .c =3D &pll_characteristics, + .t =3D PLL_TYPE_FRAC, + .f =3D CLK_SET_RATE_GATE, + }, + + [PLL_COMPID_DIV0] =3D { + .n =3D "ethpll_divpmcck", + .p =3D SAMA7D65_PLL_PARENT_FRACCK, + .l =3D &pll_layout_divpmc, + .c =3D &pll_characteristics, + .t =3D PLL_TYPE_DIV, + .f =3D CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | + CLK_SET_RATE_PARENT, + .eid =3D PMC_ETHPLL, + }, + }, + + [PLL_ID_LVDS] =3D { + [PLL_COMPID_FRAC] =3D { + .n =3D "lvdspll_fracck", + .p =3D SAMA7D65_PLL_PARENT_MAIN_XTAL, + .l =3D &pll_layout_frac, + .c =3D &lvdspll_characteristics, + .t =3D PLL_TYPE_FRAC, + .f =3D CLK_SET_RATE_GATE, + }, + + [PLL_COMPID_DIV0] =3D { + .n =3D "lvdspll_divpmcck", + .p =3D SAMA7D65_PLL_PARENT_FRACCK, + .l =3D &pll_layout_divpmc, + .c =3D &lvdspll_characteristics, + .t =3D PLL_TYPE_DIV, + .f =3D CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | + CLK_SET_RATE_PARENT, + .eid =3D PMC_LVDSPLL, + }, + }, + + [PLL_ID_USB] =3D { + [PLL_COMPID_FRAC] =3D { + .n =3D "usbpll_fracck", + .p =3D SAMA7D65_PLL_PARENT_MAIN_XTAL, + .l =3D &pll_layout_frac, + .c =3D &upll_characteristics, + .t =3D PLL_TYPE_FRAC, + .f =3D CLK_SET_RATE_GATE, + }, + + [PLL_COMPID_DIV0] =3D { + .n =3D "usbpll_divpmcck", + .p =3D SAMA7D65_PLL_PARENT_FRACCK, + .l =3D &pll_layout_divpmc, + .c =3D &upll_characteristics, + .t =3D PLL_TYPE_DIV, + .f =3D CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | + CLK_SET_RATE_PARENT, + .eid =3D PMC_UTMI, + }, + }, +}; + +/* Used to create an array entry identifying a PLL by its components. */ +#define PLL_IDS_TO_ARR_ENTRY(_id, _comp) { PLL_ID_##_id, PLL_COMPID_##_com= p} + +/* + * Master clock (MCK[0..9]) description + * @n: clock name + * @ep_chg_chg_id: index in parents array that specifies the changeable + * @ep: extra parents names array (entry formed by PLL components + * identifiers (see enum pll_component_id)) + * @hw: pointer to clk_hw + * parent + * @ep_count: extra parents count + * @ep_mux_table: mux table for extra parents + * @id: clock id + * @eid: export index in sama7d65->chws[] array + * @c: true if clock is critical and cannot be disabled + */ +static struct { + const char *n; + struct { + int pll_id; + int pll_compid; + } ep[4]; + struct clk_hw *hw; + int ep_chg_id; + u8 ep_count; + u8 ep_mux_table[4]; + u8 id; + u8 eid; + u8 c; +} sama7d65_mckx[] =3D { + { .n =3D "mck0", }, /* Dummy entry for MCK0 to store hw in probe. */ + { .n =3D "mck1", + .id =3D 1, + .ep =3D { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .ep_mux_table =3D { 5, }, + .ep_count =3D 1, + .ep_chg_id =3D INT_MIN, + .eid =3D PMC_MCK1, + .c =3D 1, }, + + { .n =3D "mck2", + .id =3D 2, + .ep =3D { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(DDR, DI= V0), }, + .ep_mux_table =3D { 5, 6, }, + .ep_count =3D 2, + .ep_chg_id =3D INT_MIN, + .c =3D 1, }, + + { .n =3D "mck3", + .id =3D 3, + .ep =3D { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(DDR, DI= V0), }, + .ep_mux_table =3D { 5, 6, }, + .ep_count =3D 2, + .ep_chg_id =3D INT_MIN, + .eid =3D PMC_MCK3, + .c =3D 1, }, + + { .n =3D "mck4", + .id =3D 4, + .ep =3D { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .ep_mux_table =3D { 5, }, + .ep_count =3D 1, + .ep_chg_id =3D INT_MIN, + .c =3D 1, }, + + { .n =3D "mck5", + .id =3D 5, + .ep =3D { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .ep_mux_table =3D { 5, }, + .ep_count =3D 1, + .ep_chg_id =3D INT_MIN, + .eid =3D PMC_MCK5, + .c =3D 1, }, + + { .n =3D "mck6", + .id =3D 6, + .ep =3D { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .ep_mux_table =3D { 5, }, + .ep_chg_id =3D INT_MIN, + .ep_count =3D 1, + .c =3D 1, }, + + { .n =3D "mck7", + .id =3D 7, + .ep =3D { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .ep_mux_table =3D { 5, }, + .ep_chg_id =3D INT_MIN, + .ep_count =3D 1, }, + + { .n =3D "mck8", + .id =3D 8, + .ep =3D { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .ep_mux_table =3D { 5, }, + .ep_chg_id =3D INT_MIN, + .ep_count =3D 1, }, + + { .n =3D "mck9", + .id =3D 9, + .ep =3D { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .ep_mux_table =3D { 5, }, + .ep_chg_id =3D INT_MIN, + .ep_count =3D 1, }, +}; + +/* + * System clock description + * @n: clock name + * @p: clock parent name + * @id: clock id + */ +static const struct { + const char *n; + const char *p; + u8 id; +} sama7d65_systemck[] =3D { + { .n =3D "uhpck", .p =3D "usbck", .id =3D 6 }, + { .n =3D "pck0", .p =3D "prog0", .id =3D 8, }, + { .n =3D "pck1", .p =3D "prog1", .id =3D 9, }, + { .n =3D "pck2", .p =3D "prog2", .id =3D 10, }, + { .n =3D "pck3", .p =3D "prog3", .id =3D 11, }, + { .n =3D "pck4", .p =3D "prog4", .id =3D 12, }, + { .n =3D "pck5", .p =3D "prog5", .id =3D 13, }, + { .n =3D "pck6", .p =3D "prog6", .id =3D 14, }, + { .n =3D "pck7", .p =3D "prog7", .id =3D 15, }, +}; + +/* Mux table for programmable clocks. */ +static u32 sama7d65_prog_mux_table[] =3D { 0, 1, 2, 5, 7, 8, 9, 10, 12 }; + +/* + * Peripheral clock parent hw identifier (used to index in sama7d65_mckx[]) + * @PCK_PARENT_HW_MCK0: pck parent hw identifier is MCK0 + * @PCK_PARENT_HW_MCK1: pck parent hw identifier is MCK1 + * @PCK_PARENT_HW_MCK2: pck parent hw identifier is MCK2 + * @PCK_PARENT_HW_MCK3: pck parent hw identifier is MCK3 + * @PCK_PARENT_HW_MCK4: pck parent hw identifier is MCK4 + * @PCK_PARENT_HW_MCK5: pck parent hw identifier is MCK5 + * @PCK_PARENT_HW_MCK6: pck parent hw identifier is MCK6 + * @PCK_PARENT_HW_MCK7: pck parent hw identifier is MCK7 + * @PCK_PARENT_HW_MCK8: pck parent hw identifier is MCK8 + * @PCK_PARENT_HW_MCK9: pck parent hw identifier is MCK9 + * @PCK_PARENT_HW_MAX: max identifier + */ +enum sama7d65_pck_parent_hw_id { + PCK_PARENT_HW_MCK0, + PCK_PARENT_HW_MCK1, + PCK_PARENT_HW_MCK2, + PCK_PARENT_HW_MCK3, + PCK_PARENT_HW_MCK4, + PCK_PARENT_HW_MCK5, + PCK_PARENT_HW_MCK6, + PCK_PARENT_HW_MCK7, + PCK_PARENT_HW_MCK8, + PCK_PARENT_HW_MCK9, + PCK_PARENT_HW_MAX +}; + +/* + * Peripheral clock description + * @n: clock name + * @p: clock parent hw id + * @r: clock range values + * @id: clock id + * @chgp: index in parent array of the changeable parent + */ +static struct { + const char *n; + enum sama7d65_pck_parent_hw_id p; + struct clk_range r; + u8 chgp; + u8 id; +} sama7d65_periphck[] =3D { + { .n =3D "pioA_clk", .p =3D PCK_PARENT_HW_MCK0, .id =3D 10, }, + { .n =3D "securam_clk", .p =3D PCK_PARENT_HW_MCK0, .id =3D 17, }, + { .n =3D "sfr_clk", .p =3D PCK_PARENT_HW_MCK7, .id =3D 18, }, + { .n =3D "hsmc_clk", .p =3D PCK_PARENT_HW_MCK5, .id =3D 20, }, + { .n =3D "xdmac0_clk", .p =3D PCK_PARENT_HW_MCK6, .id =3D 21, }, + { .n =3D "xdmac1_clk", .p =3D PCK_PARENT_HW_MCK6, .id =3D 22, }, + { .n =3D "xdmac2_clk", .p =3D PCK_PARENT_HW_MCK1, .id =3D 23, }, + { .n =3D "acc_clk", .p =3D PCK_PARENT_HW_MCK7, .id =3D 24, }, + { .n =3D "aes_clk", .p =3D PCK_PARENT_HW_MCK6, .id =3D 26, }, + { .n =3D "tzaesbasc_clk", .p =3D PCK_PARENT_HW_MCK8, .id =3D 27, }, + { .n =3D "asrc_clk", .p =3D PCK_PARENT_HW_MCK9, .id =3D 29, .r =3D { .max= =3D 200000000, }, }, + { .n =3D "cpkcc_clk", .p =3D PCK_PARENT_HW_MCK0, .id =3D 30, }, + { .n =3D "eic_clk", .p =3D PCK_PARENT_HW_MCK7, .id =3D 33, }, + { .n =3D "flex0_clk", .p =3D PCK_PARENT_HW_MCK7, .id =3D 34, }, + { .n =3D "flex1_clk", .p =3D PCK_PARENT_HW_MCK7, .id =3D 35, }, + { .n =3D "flex2_clk", .p =3D PCK_PARENT_HW_MCK7, .id =3D 36, }, + { .n =3D "flex3_clk", .p =3D PCK_PARENT_HW_MCK7, .id =3D 37, }, + { .n =3D "flex4_clk", .p =3D PCK_PARENT_HW_MCK8, .id =3D 38, }, + { .n =3D "flex5_clk", .p =3D PCK_PARENT_HW_MCK8, .id =3D 39, }, + { .n =3D "flex6_clk", .p =3D PCK_PARENT_HW_MCK8, .id =3D 40, }, + { .n =3D "flex7_clk", .p =3D PCK_PARENT_HW_MCK8, .id =3D 41, }, + { .n =3D "flex8_clk", .p =3D PCK_PARENT_HW_MCK9, .id =3D 42, }, + { .n =3D "flex9_clk", .p =3D PCK_PARENT_HW_MCK9, .id =3D 43, }, + { .n =3D "flex10_clk", .p =3D PCK_PARENT_HW_MCK9, .id =3D 44, }, + { .n =3D "gmac0_clk", .p =3D PCK_PARENT_HW_MCK6, .id =3D 46, }, + { .n =3D "gmac1_clk", .p =3D PCK_PARENT_HW_MCK6, .id =3D 47, }, + { .n =3D "gmac0_tsu_clk", .p =3D PCK_PARENT_HW_MCK1, .id =3D 49, }, + { .n =3D "gmac1_tsu_clk", .p =3D PCK_PARENT_HW_MCK1, .id =3D 50, }, + { .n =3D "icm_clk", .p =3D PCK_PARENT_HW_MCK5, .id =3D 53, }, + { .n =3D "i2smcc0_clk", .p =3D PCK_PARENT_HW_MCK9, .id =3D 54, .r =3D { .= max =3D 200000000, }, }, + { .n =3D "i2smcc1_clk", .p =3D PCK_PARENT_HW_MCK9, .id =3D 55, .r =3D { .= max =3D 200000000, }, }, + { .n =3D "lcd_clk", .p =3D PCK_PARENT_HW_MCK3, .id =3D 56, }, + { .n =3D "matrix_clk", .p =3D PCK_PARENT_HW_MCK5, .id =3D 57, }, + { .n =3D "mcan0_clk", .p =3D PCK_PARENT_HW_MCK5, .id =3D 58, .r =3D { .ma= x =3D 200000000, }, }, + { .n =3D "mcan1_clk", .p =3D PCK_PARENT_HW_MCK5, .id =3D 59, .r =3D { .ma= x =3D 200000000, }, }, + { .n =3D "mcan2_clk", .p =3D PCK_PARENT_HW_MCK5, .id =3D 60, .r =3D { .ma= x =3D 200000000, }, }, + { .n =3D "mcan3_clk", .p =3D PCK_PARENT_HW_MCK5, .id =3D 61, .r =3D { .ma= x =3D 200000000, }, }, + { .n =3D "mcan4_clk", .p =3D PCK_PARENT_HW_MCK5, .id =3D 62, .r =3D { .ma= x =3D 200000000, }, }, + { .n =3D "pdmc0_clk", .p =3D PCK_PARENT_HW_MCK9, .id =3D 64, .r =3D { .ma= x =3D 200000000, }, }, + { .n =3D "pdmc1_clk", .p =3D PCK_PARENT_HW_MCK9, .id =3D 65, .r =3D { .ma= x =3D 200000000, }, }, + { .n =3D "pit64b0_clk", .p =3D PCK_PARENT_HW_MCK7, .id =3D 66, }, + { .n =3D "pit64b1_clk", .p =3D PCK_PARENT_HW_MCK7, .id =3D 67, }, + { .n =3D "pit64b2_clk", .p =3D PCK_PARENT_HW_MCK7, .id =3D 68, }, + { .n =3D "pit64b3_clk", .p =3D PCK_PARENT_HW_MCK8, .id =3D 69, }, + { .n =3D "pit64b4_clk", .p =3D PCK_PARENT_HW_MCK8, .id =3D 70, }, + { .n =3D "pit64b5_clk", .p =3D PCK_PARENT_HW_MCK8, .id =3D 71, }, + { .n =3D "pwm_clk", .p =3D PCK_PARENT_HW_MCK7, .id =3D 72, }, + { .n =3D "qspi0_clk", .p =3D PCK_PARENT_HW_MCK5, .id =3D 73, }, + { .n =3D "qspi1_clk", .p =3D PCK_PARENT_HW_MCK5, .id =3D 74, }, + { .n =3D "sdmmc0_clk", .p =3D PCK_PARENT_HW_MCK1, .id =3D 75, }, + { .n =3D "sdmmc1_clk", .p =3D PCK_PARENT_HW_MCK1, .id =3D 76, }, + { .n =3D "sdmmc2_clk", .p =3D PCK_PARENT_HW_MCK1, .id =3D 77, }, + { .n =3D "sha_clk", .p =3D PCK_PARENT_HW_MCK6, .id =3D 78, }, + { .n =3D "spdifrx_clk", .p =3D PCK_PARENT_HW_MCK9, .id =3D 79, .r =3D { .= max =3D 200000000, }, }, + { .n =3D "spdiftx_clk", .p =3D PCK_PARENT_HW_MCK9, .id =3D 80, .r =3D { .= max =3D 200000000, }, }, + { .n =3D "ssc0_clk", .p =3D PCK_PARENT_HW_MCK7, .id =3D 81, .r =3D { .max= =3D 200000000, }, }, + { .n =3D "ssc1_clk", .p =3D PCK_PARENT_HW_MCK8, .id =3D 82, .r =3D { .max= =3D 200000000, }, }, + { .n =3D "tcb0_ch0_clk", .p =3D PCK_PARENT_HW_MCK8, .id =3D 83, .r =3D { = .max =3D 200000000, }, }, + { .n =3D "tcb0_ch1_clk", .p =3D PCK_PARENT_HW_MCK8, .id =3D 84, .r =3D { = .max =3D 200000000, }, }, + { .n =3D "tcb0_ch2_clk", .p =3D PCK_PARENT_HW_MCK8, .id =3D 85, .r =3D { = .max =3D 200000000, }, }, + { .n =3D "tcb1_ch0_clk", .p =3D PCK_PARENT_HW_MCK5, .id =3D 86, .r =3D { = .max =3D 200000000, }, }, + { .n =3D "tcb1_ch1_clk", .p =3D PCK_PARENT_HW_MCK5, .id =3D 87, .r =3D { = .max =3D 200000000, }, }, + { .n =3D "tcb1_ch2_clk", .p =3D PCK_PARENT_HW_MCK5, .id =3D 88, .r =3D { = .max =3D 200000000, }, }, + { .n =3D "tcpca_clk", .p =3D PCK_PARENT_HW_MCK5, .id =3D 89, }, + { .n =3D "tcpcb_clk", .p =3D PCK_PARENT_HW_MCK5, .id =3D 90, }, + { .n =3D "tdes_clk", .p =3D PCK_PARENT_HW_MCK6, .id =3D 91, }, + { .n =3D "trng_clk", .p =3D PCK_PARENT_HW_MCK6, .id =3D 92, }, + { .n =3D "udphsa_clk", .p =3D PCK_PARENT_HW_MCK5, .id =3D 99, }, + { .n =3D "udphsb_clk", .p =3D PCK_PARENT_HW_MCK5, .id =3D 100, }, + { .n =3D "uhphs_clk", .p =3D PCK_PARENT_HW_MCK5, .id =3D 101, }, + { .n =3D "dsi_clk", .p =3D PCK_PARENT_HW_MCK3, .id =3D 103, }, + { .n =3D "lvdsc_clk", .p =3D PCK_PARENT_HW_MCK3, .id =3D 104, }, +}; + +/* + * Generic clock description + * @n: clock name + * @pp: PLL parents (entry formed by PLL components identifiers + * (see enum pll_component_id)) + * @pp_mux_table: PLL parents mux table + * @r: clock output range + * @pp_chg_id: id in parent array of changeable PLL parent + * @pp_count: PLL parents count + * @id: clock id + */ +static const struct { + const char *n; + struct { + int pll_id; + int pll_compid; + } pp[8]; + const char pp_mux_table[8]; + struct clk_range r; + int pp_chg_id; + u8 pp_count; + u8 id; +} sama7d65_gck[] =3D { + { .n =3D "adc_gclk", + .id =3D 25, + .r =3D { .max =3D 100000000, }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO,= DIV0), }, + .pp_mux_table =3D { 8, 9, }, + .pp_count =3D 2, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "asrc_gclk", + .id =3D 29, + .r =3D { .max =3D 200000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), }, + .pp_mux_table =3D { 9, }, + .pp_count =3D 1, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "flex0_gclk", + .id =3D 34, + .r =3D { .max =3D 34000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table =3D {8, }, + .pp_count =3D 1, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "flex1_gclk", + .id =3D 35, + .r =3D { .max =3D 34000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table =3D {8, }, + .pp_count =3D 1, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "flex2_gclk", + .id =3D 36, + .r =3D { .max =3D 34000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table =3D {8, }, + .pp_count =3D 1, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "flex3_gclk", + .id =3D 37, + .r =3D { .max =3D 34000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table =3D {8, }, + .pp_count =3D 1, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "flex4_gclk", + .id =3D 38, + .r =3D { .max =3D 34000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table =3D { 8, }, + .pp_count =3D 1, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "flex5_gclk", + .id =3D 39, + .r =3D { .max =3D 34000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table =3D { 8, }, + .pp_count =3D 1, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "flex6_gclk", + .id =3D 40, + .r =3D { .max =3D 34000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table =3D { 8, }, + .pp_count =3D 1, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "flex7_gclk", + .id =3D 41, + .r =3D { .max =3D 34000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table =3D { 8, }, + .pp_count =3D 1, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "flex8_gclk", + .id =3D 42, + .r =3D { .max =3D 34000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table =3D { 8, }, + .pp_count =3D 1, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "flex9_gclk", + .id =3D 43, + .r =3D { .max =3D 34000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table =3D { 8, }, + .pp_count =3D 1, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "flex10_gclk", + .id =3D 44, + .r =3D { .max =3D 34000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table =3D { 8, }, + .pp_count =3D 1, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "gmac0_gclk", + .id =3D 46, + .r =3D { .max =3D 125000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table =3D { 10, }, + .pp_count =3D 1, + .pp_chg_id =3D 4, }, + + { .n =3D "gmac1_gclk", + .id =3D 47, + .r =3D { .max =3D 125000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table =3D { 10, }, + .pp_count =3D 1, + .pp_chg_id =3D 4, }, + + { .n =3D "gmac0_tsu_gclk", + .id =3D 49, + .r =3D { .max =3D 400000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table =3D {10, }, + .pp_count =3D 1, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "gmac1_tsu_gclk", + .id =3D 50, + .r =3D { .max =3D 400000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table =3D { 10, }, + .pp_count =3D 1, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "i2smcc0_gclk", + .id =3D 54, + .r =3D { .max =3D 100000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), }, + .pp_mux_table =3D { 9, }, + .pp_count =3D 1, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "i2smcc1_gclk", + .id =3D 55, + .r =3D { .max =3D 100000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), }, + .pp_mux_table =3D { 9, }, + .pp_count =3D 1, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "lcdc_gclk", + .id =3D 56, + .r =3D { .max =3D 90000000 }, + .pp_count =3D 0, + .pp_chg_id =3D INT_MIN, + }, + + { .n =3D "mcan0_gclk", + .id =3D 58, + .r =3D { .max =3D 80000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(USB, DIV0), }, + .pp_mux_table =3D { 12 }, + .pp_count =3D 1, + .pp_chg_id =3D 4, }, + + { .n =3D "mcan1_gclk", + .id =3D 59, + .r =3D { .max =3D 80000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(USB, DIV0), }, + .pp_mux_table =3D { 12 }, + .pp_count =3D 1, + .pp_chg_id =3D 4, }, + + { .n =3D "mcan2_gclk", + .id =3D 60, + .r =3D { .max =3D 80000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(USB, DIV0), }, + .pp_mux_table =3D { 12 }, + .pp_count =3D 1, + .pp_chg_id =3D 4, }, + + { .n =3D "mcan3_gclk", + .id =3D 61, + .r =3D { .max =3D 80000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(USB, DIV0), }, + .pp_mux_table =3D { 12 }, + .pp_count =3D 1, + .pp_chg_id =3D 4, }, + + { .n =3D "mcan4_gclk", + .id =3D 62, + .r =3D { .max =3D 80000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(USB, DIV0), }, + .pp_mux_table =3D { 12 }, + .pp_count =3D 1, + .pp_chg_id =3D 4, }, + + { .n =3D "pdmc0_gclk", + .id =3D 64, + .r =3D { .max =3D 80000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), }, + .pp_mux_table =3D { 9 }, + .pp_count =3D 1, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "pdmc1_gclk", + .id =3D 65, + .r =3D { .max =3D 80000000, }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), }, + .pp_mux_table =3D { 9, }, + .pp_count =3D 1, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "pit64b0_gclk", + .id =3D 66, + .r =3D { .max =3D 34000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO,= DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table =3D { 8, 9, 10, }, + .pp_count =3D 3, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "pit64b1_gclk", + .id =3D 67, + .r =3D { .max =3D 34000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO,= DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table =3D { 8, 9, 10, }, + .pp_count =3D 3, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "pit64b2_gclk", + .id =3D 68, + .r =3D { .max =3D 34000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO,= DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table =3D { 8, 9, 10, }, + .pp_count =3D 3, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "pit64b3_gclk", + .id =3D 69, + .r =3D { .max =3D 34000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO,= DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table =3D {8, 9, 10, }, + .pp_count =3D 3, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "pit64b4_gclk", + .id =3D 70, + .r =3D { .max =3D 34000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO,= DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table =3D {8, 9, 10, }, + .pp_count =3D 3, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "pit64b5_gclk", + .id =3D 71, + .r =3D { .max =3D 34000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO,= DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table =3D {8, 9, 10, }, + .pp_count =3D 3, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "qspi0_gclk", + .id =3D 73, + .r =3D { .max =3D 400000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, D= IV0), }, + .pp_mux_table =3D { 5, 8, }, + .pp_count =3D 2, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "qspi1_gclk", + .id =3D 74, + .r =3D { .max =3D 266000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, D= IV0), }, + .pp_mux_table =3D { 5, 8, }, + .pp_count =3D 2, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "sdmmc0_gclk", + .id =3D 75, + .r =3D { .max =3D 208000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(ETH, D= IV0), }, + .pp_mux_table =3D { 8, 10, }, + .pp_count =3D 2, + .pp_chg_id =3D 4, }, + + { .n =3D "sdmmc1_gclk", + .id =3D 76, + .r =3D { .max =3D 208000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(ETH, D= IV0), }, + .pp_mux_table =3D { 8, 10, }, + .pp_count =3D 2, + .pp_chg_id =3D 4, }, + + { .n =3D "sdmmc2_gclk", + .id =3D 77, + .r =3D { .max =3D 208000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(ETH, D= IV0), }, + .pp_mux_table =3D { 8, 10 }, + .pp_count =3D 2, + .pp_chg_id =3D 4, }, + + { .n =3D "spdifrx_gclk", + .id =3D 79, + .r =3D { .max =3D 150000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), }, + .pp_mux_table =3D { 9, }, + .pp_count =3D 1, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "spdiftx_gclk", + .id =3D 80, + .r =3D { .max =3D 25000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), }, + .pp_mux_table =3D { 9, }, + .pp_count =3D 1, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "tcb0_ch0_gclk", + .id =3D 83, + .r =3D { .max =3D 34000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO,= DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table =3D { 8, 9, 10, }, + .pp_count =3D 3, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "tcb1_ch0_gclk", + .id =3D 86, + .r =3D { .max =3D 67000000 }, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO,= DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table =3D { 8, 9, 10, }, + .pp_count =3D 3, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "DSI_gclk", + .id =3D 103, + .r =3D {.max =3D 27000000}, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .pp_mux_table =3D {5}, + .pp_count =3D 1, + .pp_chg_id =3D INT_MIN, }, + + { .n =3D "I3CC_gclk", + .id =3D 105, + .r =3D {.max =3D 125000000}, + .pp =3D { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO,= DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table =3D {8, 9, 10, }, + .pp_count =3D 3, + .pp_chg_id =3D INT_MIN, }, +}; + +/* MCK0 characteristics. */ +static const struct clk_master_characteristics mck0_characteristics =3D { + .output =3D { .min =3D 32768, .max =3D 200000000 }, + .divisors =3D { 1, 2, 4, 3, 5 }, + .have_div3_pres =3D 1, +}; + +/* MCK0 layout. */ +static const struct clk_master_layout mck0_layout =3D { + .mask =3D 0x773, + .pres_shift =3D 4, + .offset =3D 0x28, +}; + +/* Programmable clock layout. */ +static const struct clk_programmable_layout programmable_layout =3D { + .pres_mask =3D 0xff, + .pres_shift =3D 8, + .css_mask =3D 0x1f, + .have_slck_mck =3D 0, + .is_pres_direct =3D 1, +}; + +/* Peripheral clock layout. */ +static const struct clk_pcr_layout sama7d65_pcr_layout =3D { + .offset =3D 0x88, + .cmd =3D BIT(31), + .gckcss_mask =3D GENMASK(12, 8), + .pid_mask =3D GENMASK(6, 0), +}; + +static void __init sama7d65_pmc_setup(struct device_node *np) +{ + const char *main_xtal_name =3D "main_xtal"; + struct pmc_data *sama7d65_pmc; + const char *parent_names[11]; + void **alloc_mem =3D NULL; + int alloc_mem_size =3D 0; + struct regmap *regmap; + struct clk_hw *hw, *main_rc_hw, *main_osc_hw, *main_xtal_hw; + struct clk_hw *td_slck_hw, *md_slck_hw; + static struct clk_parent_data parent_data; + struct clk_hw *parent_hws[10]; + bool bypass; + int i, j; + + td_slck_hw =3D __clk_get_hw(of_clk_get_by_name(np, "td_slck")); + md_slck_hw =3D __clk_get_hw(of_clk_get_by_name(np, "md_slck")); + main_xtal_hw =3D __clk_get_hw(of_clk_get_by_name(np, main_xtal_name)); + + if (!td_slck_hw || !md_slck_hw || !main_xtal_hw) + return; + + regmap =3D device_node_to_regmap(np); + if (IS_ERR(regmap)) + return; + + sama7d65_pmc =3D pmc_data_allocate(PMC_INDEX_MAX, + nck(sama7d65_systemck), + nck(sama7d65_periphck), + nck(sama7d65_gck), 8); + if (!sama7d65_pmc) + return; + + alloc_mem =3D kmalloc(sizeof(void *) * + (ARRAY_SIZE(sama7d65_mckx) + ARRAY_SIZE(sama7d65_gck)), + GFP_KERNEL); + if (!alloc_mem) + goto err_free; + + main_rc_hw =3D at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000= 000, + 50000000); + if (IS_ERR(main_rc_hw)) + goto err_free; + + bypass =3D of_property_read_bool(np, "atmel,osc-bypass"); + + parent_data.name =3D main_xtal_name; + parent_data.fw_name =3D main_xtal_name; + main_osc_hw =3D at91_clk_register_main_osc(regmap, "main_osc", NULL, + &parent_data, bypass); + if (IS_ERR(main_osc_hw)) + goto err_free; + + parent_hws[0] =3D main_rc_hw; + parent_hws[1] =3D main_osc_hw; + hw =3D at91_clk_register_sam9x5_main(regmap, "mainck", NULL, parent_hws, = 2); + if (IS_ERR(hw)) + goto err_free; + + sama7d65_pmc->chws[PMC_MAIN] =3D hw; + + for (i =3D 0; i < PLL_ID_MAX; i++) { + for (j =3D 0; j < PLL_COMPID_MAX; j++) { + struct clk_hw *parent_hw; + + if (!sama7d65_plls[i][j].n) + continue; + + switch (sama7d65_plls[i][j].t) { + case PLL_TYPE_FRAC: + switch (sama7d65_plls[i][j].p) { + case SAMA7D65_PLL_PARENT_MAINCK: + parent_hw =3D sama7d65_pmc->chws[PMC_MAIN]; + break; + case SAMA7D65_PLL_PARENT_MAIN_XTAL: + parent_hw =3D main_xtal_hw; + break; + default: + /* Should not happen. */ + parent_hw =3D NULL; + break; + } + + hw =3D sam9x60_clk_register_frac_pll(regmap, + &pmc_pll_lock, sama7d65_plls[i][j].n, + NULL, parent_hw, i, + sama7d65_plls[i][j].c, + sama7d65_plls[i][j].l, + sama7d65_plls[i][j].f); + break; + + case PLL_TYPE_DIV: + hw =3D sam9x60_clk_register_div_pll(regmap, + &pmc_pll_lock, sama7d65_plls[i][j].n, + NULL, sama7d65_plls[i][0].hw, i, + sama7d65_plls[i][j].c, + sama7d65_plls[i][j].l, + sama7d65_plls[i][j].f, + sama7d65_plls[i][j].safe_div); + break; + + default: + continue; + } + + if (IS_ERR(hw)) + goto err_free; + + sama7d65_plls[i][j].hw =3D hw; + if (sama7d65_plls[i][j].eid) + sama7d65_pmc->chws[sama7d65_plls[i][j].eid] =3D hw; + } + } + + hw =3D at91_clk_register_master_div(regmap, "mck0", NULL, + sama7d65_plls[PLL_ID_CPU][1].hw, + &mck0_layout, &mck0_characteristics, + &pmc_mck0_lock, CLK_GET_RATE_NOCACHE, 5); + if (IS_ERR(hw)) + goto err_free; + + sama7d65_pmc->chws[PMC_MCK] =3D hw; + sama7d65_mckx[PCK_PARENT_HW_MCK0].hw =3D hw; + + parent_hws[0] =3D md_slck_hw; + parent_hws[1] =3D td_slck_hw; + parent_hws[2] =3D sama7d65_pmc->chws[PMC_MAIN]; + for (i =3D PCK_PARENT_HW_MCK1; i < ARRAY_SIZE(sama7d65_mckx); i++) { + u8 num_parents =3D 3 + sama7d65_mckx[i].ep_count; + struct clk_hw *tmp_parent_hws[8]; + u32 *mux_table; + + mux_table =3D kmalloc_array(num_parents, sizeof(*mux_table), + GFP_KERNEL); + if (!mux_table) + goto err_free; + + PMC_INIT_TABLE(mux_table, 3); + PMC_FILL_TABLE(&mux_table[3], sama7d65_mckx[i].ep_mux_table, + sama7d65_mckx[i].ep_count); + for (j =3D 0; j < sama7d65_mckx[i].ep_count; j++) { + u8 pll_id =3D sama7d65_mckx[i].ep[j].pll_id; + u8 pll_compid =3D sama7d65_mckx[i].ep[j].pll_compid; + + tmp_parent_hws[j] =3D sama7d65_plls[pll_id][pll_compid].hw; + } + PMC_FILL_TABLE(&parent_hws[3], tmp_parent_hws, + sama7d65_mckx[i].ep_count); + + hw =3D at91_clk_sama7g5_register_master(regmap, sama7d65_mckx[i].n, + num_parents, NULL, parent_hws, + mux_table, &pmc_mckX_lock, + sama7d65_mckx[i].id, + sama7d65_mckx[i].c, + sama7d65_mckx[i].ep_chg_id); + alloc_mem[alloc_mem_size++] =3D mux_table; + + if (IS_ERR(hw)) { + kfree(mux_table); + goto err_free; + } + + sama7d65_mckx[i].hw =3D hw; + if (sama7d65_mckx[i].eid) + sama7d65_pmc->chws[sama7d65_mckx[i].eid] =3D hw; + } + + parent_names[0] =3D "syspll_divpmcck"; + parent_names[1] =3D "usbpll_divpmcck"; + parent_names[2] =3D "main_osc"; + hw =3D sam9x60_clk_register_usb(regmap, "usbck", parent_names, 3); + if (IS_ERR(hw)) + goto err_free; + + parent_hws[0] =3D md_slck_hw; + parent_hws[1] =3D td_slck_hw; + parent_hws[2] =3D sama7d65_pmc->chws[PMC_MAIN]; + parent_hws[3] =3D sama7d65_plls[PLL_ID_SYS][PLL_COMPID_DIV0].hw; + parent_hws[4] =3D sama7d65_plls[PLL_ID_DDR][PLL_COMPID_DIV0].hw; + parent_hws[5] =3D sama7d65_plls[PLL_ID_GPU][PLL_COMPID_DIV0].hw; + parent_hws[6] =3D sama7d65_plls[PLL_ID_BAUD][PLL_COMPID_DIV0].hw; + parent_hws[7] =3D sama7d65_plls[PLL_ID_AUDIO][PLL_COMPID_DIV0].hw; + parent_hws[8] =3D sama7d65_plls[PLL_ID_ETH][PLL_COMPID_DIV0].hw; + + for (i =3D 0; i < 8; i++) { + char name[6]; + + snprintf(name, sizeof(name), "prog%d", i); + + hw =3D at91_clk_register_programmable(regmap, name, NULL, parent_hws, + 9, i, + &programmable_layout, + sama7d65_prog_mux_table); + if (IS_ERR(hw)) + goto err_free; + + sama7d65_pmc->pchws[i] =3D hw; + } + + for (i =3D 0; i < ARRAY_SIZE(sama7d65_systemck); i++) { + hw =3D at91_clk_register_system(regmap, sama7d65_systemck[i].n, + sama7d65_systemck[i].p, NULL, + sama7d65_systemck[i].id, 0); + if (IS_ERR(hw)) + goto err_free; + + sama7d65_pmc->shws[sama7d65_systemck[i].id] =3D hw; + } + + for (i =3D 0; i < ARRAY_SIZE(sama7d65_periphck); i++) { + hw =3D at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &sama7d65_pcr_layout, + sama7d65_periphck[i].n, + NULL, + sama7d65_mckx[sama7d65_periphck[i].p].hw, + sama7d65_periphck[i].id, + &sama7d65_periphck[i].r, + sama7d65_periphck[i].chgp ? 0 : + INT_MIN, 0); + if (IS_ERR(hw)) + goto err_free; + + sama7d65_pmc->phws[sama7d65_periphck[i].id] =3D hw; + } + + parent_hws[0] =3D md_slck_hw; + parent_hws[1] =3D td_slck_hw; + parent_hws[2] =3D sama7d65_pmc->chws[PMC_MAIN]; + parent_hws[3] =3D sama7d65_pmc->chws[PMC_MCK1]; + for (i =3D 0; i < ARRAY_SIZE(sama7d65_gck); i++) { + u8 num_parents =3D 4 + sama7d65_gck[i].pp_count; + struct clk_hw *tmp_parent_hws[8]; + u32 *mux_table; + + mux_table =3D kmalloc_array(num_parents, sizeof(*mux_table), + GFP_KERNEL); + if (!mux_table) + goto err_free; + + PMC_INIT_TABLE(mux_table, 4); + PMC_FILL_TABLE(&mux_table[4], sama7d65_gck[i].pp_mux_table, + sama7d65_gck[i].pp_count); + for (j =3D 0; j < sama7d65_gck[i].pp_count; j++) { + u8 pll_id =3D sama7d65_gck[i].pp[j].pll_id; + u8 pll_compid =3D sama7d65_gck[i].pp[j].pll_compid; + + tmp_parent_hws[j] =3D sama7d65_plls[pll_id][pll_compid].hw; + } + PMC_FILL_TABLE(&parent_hws[4], tmp_parent_hws, + sama7d65_gck[i].pp_count); + + hw =3D at91_clk_register_generated(regmap, &pmc_pcr_lock, + &sama7d65_pcr_layout, + sama7d65_gck[i].n, NULL, + parent_hws, mux_table, + num_parents, + sama7d65_gck[i].id, + &sama7d65_gck[i].r, + sama7d65_gck[i].pp_chg_id); + if (IS_ERR(hw)) + goto err_free; + + sama7d65_pmc->ghws[sama7d65_gck[i].id] =3D hw; + alloc_mem[alloc_mem_size++] =3D mux_table; + } + + of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sama7d65_pmc); + kfree(alloc_mem); + + return; + +err_free: + if (alloc_mem) { + for (i =3D 0; i < alloc_mem_size; i++) + kfree(alloc_mem[i]); + kfree(alloc_mem); + } + + kfree(sama7d65_pmc); +} + +/* Some clks are used for a clocksource */ +CLK_OF_DECLARE(sama7d65_pmc, "microchip,sama7d65-pmc", sama7d65_pmc_setup); --=20 2.43.0