aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS2
-rw-r--r--arch/arm/dts/sama7g5-pinfunc.h924
-rw-r--r--arch/arm/mach-at91/Kconfig4
-rw-r--r--arch/arm/mach-at91/armv7/Makefile1
-rw-r--r--arch/arm/mach-at91/armv7/cpu.c2
-rw-r--r--arch/arm/mach-at91/armv7/sama7g5_devices.c11
-rw-r--r--arch/arm/mach-at91/include/mach/at91_common.h1
-rw-r--r--arch/arm/mach-at91/include/mach/hardware.h2
-rw-r--r--arch/arm/mach-at91/include/mach/sama7g5.h74
-rw-r--r--board/atmel/common/mac_eeprom.c33
-rw-r--r--drivers/clk/at91/Kconfig7
-rw-r--r--drivers/clk/at91/Makefile15
-rw-r--r--drivers/clk/at91/clk-generated.c178
-rw-r--r--drivers/clk/at91/clk-generic.c202
-rw-r--r--drivers/clk/at91/clk-h32mx.c56
-rw-r--r--drivers/clk/at91/clk-main.c381
-rw-r--r--drivers/clk/at91/clk-master.c331
-rw-r--r--drivers/clk/at91/clk-peripheral.c291
-rw-r--r--drivers/clk/at91/clk-plla.c54
-rw-r--r--drivers/clk/at91/clk-plladiv.c85
-rw-r--r--drivers/clk/at91/clk-programmable.c208
-rw-r--r--drivers/clk/at91/clk-sam9x60-pll.c442
-rw-r--r--drivers/clk/at91/clk-slow.c36
-rw-r--r--drivers/clk/at91/clk-system.c143
-rw-r--r--drivers/clk/at91/clk-usb.c147
-rw-r--r--drivers/clk/at91/clk-utmi.c234
-rw-r--r--drivers/clk/at91/compat.c1023
-rw-r--r--drivers/clk/at91/pmc.c218
-rw-r--r--drivers/clk/at91/pmc.h140
-rw-r--r--drivers/clk/at91/sama7g5.c1401
-rw-r--r--drivers/clk/at91/sckc.c169
-rw-r--r--drivers/clk/clk-uclass.c51
-rw-r--r--drivers/clk/clk.c3
-rw-r--r--drivers/core/device.c22
-rw-r--r--drivers/cpu/Makefile1
-rw-r--r--drivers/cpu/at91_cpu.c123
-rw-r--r--drivers/mmc/atmel_sdhci.c13
-rw-r--r--drivers/pinctrl/pinctrl-at91-pio4.c1
-rw-r--r--drivers/timer/Kconfig7
-rw-r--r--drivers/timer/Makefile1
-rw-r--r--drivers/timer/mchp-pit64b-timer.c109
-rw-r--r--include/dm/device-internal.h9
-rw-r--r--include/dt-bindings/clk/at91.h22
-rw-r--r--include/linux/clk/at91_pmc.h247
-rw-r--r--test/dm/clk_ccf.c57
-rw-r--r--test/dm/core.c160
46 files changed, 6713 insertions, 928 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index c96b8b6baa1..85babd19089 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -295,7 +295,9 @@ S: Maintained
T: git https://gitlab.denx.de/u-boot/custodians/u-boot-atmel.git
F: arch/arm/mach-at91/
F: board/atmel/
+F: drivers/cpu/at91_cpu.c
F: drivers/misc/microchip_flexcom.c
+F: drivers/timer/mchp-pit64b-timer.c
ARM NEXELL S5P4418
M: Stefan Bosch <stefan_b@posteo.net>
diff --git a/arch/arm/dts/sama7g5-pinfunc.h b/arch/arm/dts/sama7g5-pinfunc.h
new file mode 100644
index 00000000000..89293e5470b
--- /dev/null
+++ b/arch/arm/dts/sama7g5-pinfunc.h
@@ -0,0 +1,924 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#define PINMUX_PIN(no, func, ioset) \
+(((no) & 0xffff) | (((func) & 0xf) << 16) | (((ioset) & 0xff) << 20))
+
+#define PIN_PA0 0
+#define PIN_PA0__GPIO PINMUX_PIN(PIN_PA0, 0, 0)
+#define PIN_PA0__SDMMC0_CK PINMUX_PIN(PIN_PA0, 1, 1)
+#define PIN_PA0__FLEXCOM0_IO0 PINMUX_PIN(PIN_PA0, 2, 1)
+#define PIN_PA0__CANTX3 PINMUX_PIN(PIN_PA0, 3, 1)
+#define PIN_PA0__PWML0 PINMUX_PIN(PIN_PA0, 5, 2)
+#define PIN_PA1 1
+#define PIN_PA1__GPIO PINMUX_PIN(PIN_PA1, 0, 0)
+#define PIN_PA1__SDMMC0_CMD PINMUX_PIN(PIN_PA1, 1, 1)
+#define PIN_PA1__FLEXCOM0_IO1 PINMUX_PIN(PIN_PA1, 2, 1)
+#define PIN_PA1__CANRX3 PINMUX_PIN(PIN_PA1, 3, 1)
+#define PIN_PA1__D14 PINMUX_PIN(PIN_PA1, 4, 1)
+#define PIN_PA1__PWMH0 PINMUX_PIN(PIN_PA1, 5, 3)
+#define PIN_PA2 2
+#define PIN_PA2__GPIO PINMUX_PIN(PIN_PA2, 0, 0)
+#define PIN_PA2__SDMMC0_RSTN PINMUX_PIN(PIN_PA2, 1, 1)
+#define PIN_PA2__FLEXCOM0_IO2 PINMUX_PIN(PIN_PA2, 2, 1)
+#define PIN_PA2__PDMC1_CLK PINMUX_PIN(PIN_PA2, 3, 1)
+#define PIN_PA2__D15 PINMUX_PIN(PIN_PA2, 4, 1)
+#define PIN_PA2__PWMH1 PINMUX_PIN(PIN_PA2, 5, 3)
+#define PIN_PA2__FLEXCOM1_IO0 PINMUX_PIN(PIN_PA2, 6, 3)
+#define PIN_PA3 3
+#define PIN_PA3__GPIO PINMUX_PIN(PIN_PA3, 0, 0)
+#define PIN_PA3__SDMMC0_DAT0 PINMUX_PIN(PIN_PA3, 1, 1)
+#define PIN_PA3__FLEXCOM0_IO3 PINMUX_PIN(PIN_PA3, 2, 1)
+#define PIN_PA3__PDMC1_DS0 PINMUX_PIN(PIN_PA3, 3, 1)
+#define PIN_PA3__NWR1_NBS1 PINMUX_PIN(PIN_PA3, 4, 1)
+#define PIN_PA3__PWML3 PINMUX_PIN(PIN_PA3, 5, 3)
+#define PIN_PA3__FLEXCOM1_IO1 PINMUX_PIN(PIN_PA3, 6, 3)
+#define PIN_PA4 4
+#define PIN_PA4__GPIO PINMUX_PIN(PIN_PA4, 0, 0)
+#define PIN_PA4__SDMMC0_DAT1 PINMUX_PIN(PIN_PA4, 1, 1)
+#define PIN_PA4__FLEXCOM0_IO4 PINMUX_PIN(PIN_PA4, 2, 1)
+#define PIN_PA4__PDMC1_DS1 PINMUX_PIN(PIN_PA4, 3, 1)
+#define PIN_PA4__NCS2 PINMUX_PIN(PIN_PA4, 4, 1)
+#define PIN_PA4__PWMH3 PINMUX_PIN(PIN_PA4, 5, 3)
+#define PIN_PA4__FLEXCOM2_IO0 PINMUX_PIN(PIN_PA4, 6, 3)
+#define PIN_PA5 5
+#define PIN_PA5__GPIO PINMUX_PIN(PIN_PA5, 0, 0)
+#define PIN_PA5__SDMMC0_DAT2 PINMUX_PIN(PIN_PA5, 1, 1)
+#define PIN_PA5__FLEXCOM1_IO0 PINMUX_PIN(PIN_PA5, 2, 1)
+#define PIN_PA5__CANTX2 PINMUX_PIN(PIN_PA5, 3, 1)
+#define PIN_PA5__A23 PINMUX_PIN(PIN_PA5, 4, 1)
+#define PIN_PA5__PWMEXTRG0 PINMUX_PIN(PIN_PA5, 5, 3)
+#define PIN_PA5__FLEXCOM2_IO1 PINMUX_PIN(PIN_PA5, 6, 3)
+#define PIN_PA6 6
+#define PIN_PA6__GPIO PINMUX_PIN(PIN_PA6, 0, 0)
+#define PIN_PA6__SDMMC0_DAT3 PINMUX_PIN(PIN_PA6, 1, 1)
+#define PIN_PA6__FLEXCOM1_IO1 PINMUX_PIN(PIN_PA6, 2, 1)
+#define PIN_PA6__CANRX2 PINMUX_PIN(PIN_PA6, 3, 1)
+#define PIN_PA6__A24 PINMUX_PIN(PIN_PA6, 4, 1)
+#define PIN_PA6__PWMEXTRG1 PINMUX_PIN(PIN_PA6, 5, 3)
+#define PIN_PA6__FLEXCOM3_IO0 PINMUX_PIN(PIN_PA6, 6, 3)
+#define PIN_PA7 7
+#define PIN_PA7__GPIO PINMUX_PIN(PIN_PA7, 0, 0)
+#define PIN_PA7__SDMMC0_DAT4 PINMUX_PIN(PIN_PA7, 1, 1)
+#define PIN_PA7__FLEXCOM2_IO0 PINMUX_PIN(PIN_PA7, 2, 1)
+#define PIN_PA7__CANTX1 PINMUX_PIN(PIN_PA7, 3, 1)
+#define PIN_PA7__NWAIT PINMUX_PIN(PIN_PA7, 4, 1)
+#define PIN_PA7__PWMFI0 PINMUX_PIN(PIN_PA7, 5, 3)
+#define PIN_PA7__FLEXCOM3_IO1 PINMUX_PIN(PIN_PA7, 6, 3)
+#define PIN_PA8 8
+#define PIN_PA8__GPIO PINMUX_PIN(PIN_PA8, 0, 0)
+#define PIN_PA8__SDMMC0_DAT5 PINMUX_PIN(PIN_PA8, 1, 1)
+#define PIN_PA8__FLEXCOM2_IO1 PINMUX_PIN(PIN_PA8, 2, 1)
+#define PIN_PA8__CANRX1 PINMUX_PIN(PIN_PA8, 3, 1)
+#define PIN_PA8__NCS0 PINMUX_PIN(PIN_PA8, 4, 1)
+#define PIN_PA8__PWMIF1 PINMUX_PIN(PIN_PA8, 5, 3)
+#define PIN_PA8__FLEXCOM4_IO0 PINMUX_PIN(PIN_PA8, 6, 3)
+#define PIN_PA9 9
+#define PIN_PA9__GPIO PINMUX_PIN(PIN_PA9, 0, 0)
+#define PIN_PA9__SDMMC0_DAT6 PINMUX_PIN(PIN_PA9, 1, 1)
+#define PIN_PA9__FLEXCOM2_IO2 PINMUX_PIN(PIN_PA9, 2, 1)
+#define PIN_PA9__CANTX0 PINMUX_PIN(PIN_PA9, 3, 1)
+#define PIN_PA9__SMCK PINMUX_PIN(PIN_PA9, 4, 1)
+#define PIN_PA9__SPDIF_RX PINMUX_PIN(PIN_PA9, 5, 1)
+#define PIN_PA9__FLEXCOM4_IO1 PINMUX_PIN(PIN_PA9, 6, 3)
+#define PIN_PA10 10
+#define PIN_PA10__GPIO PINMUX_PIN(PIN_PA10, 0, 0)
+#define PIN_PA10__SDMMC0_DAT7 PINMUX_PIN(PIN_PA10, 1, 1)
+#define PIN_PA10__FLEXCOM2_IO3 PINMUX_PIN(PIN_PA10, 2, 1)
+#define PIN_PA10__CANRX0 PINMUX_PIN(PIN_PA10, 3, 1)
+#define PIN_PA10__NCS1 PINMUX_PIN(PIN_PA10, 4, 1)
+#define PIN_PA10__SPDIF_TX PINMUX_PIN(PIN_PA10, 5, 1)
+#define PIN_PA10__FLEXCOM5_IO0 PINMUX_PIN(PIN_PA10, 6, 3)
+#define PIN_PA11 11
+#define PIN_PA11__GPIO PINMUX_PIN(PIN_PA11, 0, 0)
+#define PIN_PA11__SDMMC0_DS PINMUX_PIN(PIN_PA11, 1, 1)
+#define PIN_PA11__FLEXCOM2_IO4 PINMUX_PIN(PIN_PA11, 2, 1)
+#define PIN_PA11__A0_NBS0 PINMUX_PIN(PIN_PA11, 4, 1)
+#define PIN_PA11__TIOA0 PINMUX_PIN(PIN_PA11, 5, 1)
+#define PIN_PA11__FLEXCOM5_IO1 PINMUX_PIN(PIN_PA11, 6, 3)
+#define PIN_PA12 12
+#define PIN_PA12__GPIO PINMUX_PIN(PIN_PA12, 0, 0)
+#define PIN_PA12__SDMMC0_WP PINMUX_PIN(PIN_PA12, 1, 1)
+#define PIN_PA12__FLEXCOM1_IO3 PINMUX_PIN(PIN_PA12, 2, 1)
+#define PIN_PA12__FLEXCOM3_IO5 PINMUX_PIN(PIN_PA12, 4, 1)
+#define PIN_PA12__PWML2 PINMUX_PIN(PIN_PA12, 5, 3)
+#define PIN_PA12__FLEXCOM6_IO0 PINMUX_PIN(PIN_PA12, 6, 3)
+#define PIN_PA13 13
+#define PIN_PA13__GPIO PINMUX_PIN(PIN_PA13, 0, 0)
+#define PIN_PA13__SDMMC0_1V8SEL PINMUX_PIN(PIN_PA13, 1, 1)
+#define PIN_PA13__FLEXCOM1_IO2 PINMUX_PIN(PIN_PA13, 2, 1)
+#define PIN_PA13__FLEXCOM3_IO6 PINMUX_PIN(PIN_PA13, 4, 1)
+#define PIN_PA13__PWMH2 PINMUX_PIN(PIN_PA13, 5, 3)
+#define PIN_PA13__FLEXCOM6_IO1 PINMUX_PIN(PIN_PA13, 6, 3)
+#define PIN_PA14 14
+#define PIN_PA14__GPIO PINMUX_PIN(PIN_PA14, 0, 0)
+#define PIN_PA14__SDMMC0_CD PINMUX_PIN(PIN_PA14, 1, 1)
+#define PIN_PA14__FLEXCOM1_IO4 PINMUX_PIN(PIN_PA14, 2, 1)
+#define PIN_PA14__A25 PINMUX_PIN(PIN_PA14, 4, 1)
+#define PIN_PA14__PWML1 PINMUX_PIN(PIN_PA14, 5, 3)
+#define PIN_PA15 15
+#define PIN_PA15__GPIO PINMUX_PIN(PIN_PA15, 0, 0)
+#define PIN_PA15__G0_TXEN PINMUX_PIN(PIN_PA15, 1, 1)
+#define PIN_PA15__FLEXCOM3_IO0 PINMUX_PIN(PIN_PA15, 2, 1)
+#define PIN_PA15__ISC_MCK PINMUX_PIN(PIN_PA15, 3, 1)
+#define PIN_PA15__A1 PINMUX_PIN(PIN_PA15, 4, 1)
+#define PIN_PA15__TIOB0 PINMUX_PIN(PIN_PA15, 5, 1)
+#define PIN_PA16 16
+#define PIN_PA16__GPIO PINMUX_PIN(PIN_PA16, 0, 0)
+#define PIN_PA16__G0_TX0 PINMUX_PIN(PIN_PA16, 1, 1)
+#define PIN_PA16__FLEXCOM3_IO1 PINMUX_PIN(PIN_PA16, 2, 1)
+#define PIN_PA16__ISC_D0 PINMUX_PIN(PIN_PA16, 3, 1)
+#define PIN_PA16__A2 PINMUX_PIN(PIN_PA16, 4, 1)
+#define PIN_PA16__TCLK0 PINMUX_PIN(PIN_PA16, 5, 1)
+#define PIN_PA17 17
+#define PIN_PA17__GPIO PINMUX_PIN(PIN_PA17, 0, 0)
+#define PIN_PA17__G0_TX1 PINMUX_PIN(PIN_PA17, 1, 1)
+#define PIN_PA17__FLEXCOM3_IO2 PINMUX_PIN(PIN_PA17, 2, 1)
+#define PIN_PA17__ISC_D1 PINMUX_PIN(PIN_PA17, 3, 1)
+#define PIN_PA17__A3 PINMUX_PIN(PIN_PA17, 4, 1)
+#define PIN_PA17__TIOA1 PINMUX_PIN(PIN_PA17, 5, 1)
+#define PIN_PA18 18
+#define PIN_PA18__GPIO PINMUX_PIN(PIN_PA18, 0, 0)
+#define PIN_PA18__G0_RXDV PINMUX_PIN(PIN_PA18, 1, 1)
+#define PIN_PA18__FLEXCOM3_IO3 PINMUX_PIN(PIN_PA18, 2, 1)
+#define PIN_PA18__ISC_D2 PINMUX_PIN(PIN_PA18, 3, 1)
+#define PIN_PA18__A4 PINMUX_PIN(PIN_PA18, 4, 1)
+#define PIN_PA18__TIOB1 PINMUX_PIN(PIN_PA18, 5, 1)
+#define PIN_PA19 19
+#define PIN_PA19__GPIO PINMUX_PIN(PIN_PA19, 0, 0)
+#define PIN_PA19__G0_RX0 PINMUX_PIN(PIN_PA19, 1, 1)
+#define PIN_PA19__FLEXCOM3_IO4 PINMUX_PIN(PIN_PA19, 2, 1)
+#define PIN_PA19__ISC_D3 PINMUX_PIN(PIN_PA19, 3, 1)
+#define PIN_PA19__A5 PINMUX_PIN(PIN_PA19, 4, 1)
+#define PIN_PA19__TCLK1 PINMUX_PIN(PIN_PA19, 5, 1)
+#define PIN_PA20 20
+#define PIN_PA20__GPIO PINMUX_PIN(PIN_PA20, 0, 0)
+#define PIN_PA20__G0_RX1 PINMUX_PIN(PIN_PA20, 1, 1)
+#define PIN_PA20__FLEXCOM4_IO0 PINMUX_PIN(PIN_PA20, 2, 1)
+#define PIN_PA20__ISC_D4 PINMUX_PIN(PIN_PA20, 3, 1)
+#define PIN_PA20__A6 PINMUX_PIN(PIN_PA20, 4, 1)
+#define PIN_PA20__TIOA2 PINMUX_PIN(PIN_PA20, 5, 1)
+#define PIN_PA21 21
+#define PIN_PA21__GPIO PINMUX_PIN(PIN_PA21, 0, 0)
+#define PIN_PA21__G0_RXER PINMUX_PIN(PIN_PA21, 1, 1)
+#define PIN_PA21__FLEXCOM4_IO1 PINMUX_PIN(PIN_PA21, 2, 1)
+#define PIN_PA21__ISC_D5 PINMUX_PIN(PIN_PA21, 3, 1)
+#define PIN_PA21__A7 PINMUX_PIN(PIN_PA21, 4, 1)
+#define PIN_PA21__TIOB2 PINMUX_PIN(PIN_PA21, 5, 1)
+#define PIN_PA22 22
+#define PIN_PA22__GPIO PINMUX_PIN(PIN_PA22, 0, 0)
+#define PIN_PA22__G0_MDC PINMUX_PIN(PIN_PA22, 1, 1)
+#define PIN_PA22__FLEXCOM4_IO2 PINMUX_PIN(PIN_PA22, 2, 1)
+#define PIN_PA22__ISC_D6 PINMUX_PIN(PIN_PA22, 3, 1)
+#define PIN_PA22__A8 PINMUX_PIN(PIN_PA22, 4, 1)
+#define PIN_PA22__TCLK2 PINMUX_PIN(PIN_PA22, 5, 1)
+#define PIN_PA23 23
+#define PIN_PA23__GPIO PINMUX_PIN(PIN_PA23, 0, 0)
+#define PIN_PA23__G0_MDIO PINMUX_PIN(PIN_PA23, 1, 1)
+#define PIN_PA23__FLEXCOM4_IO3 PINMUX_PIN(PIN_PA23, 2, 1)
+#define PIN_PA23__ISC_D7 PINMUX_PIN(PIN_PA23, 3, 1)
+#define PIN_PA23__A9 PINMUX_PIN(PIN_PA23, 4, 1)
+#define PIN_PA24 24
+#define PIN_PA24__GPIO PINMUX_PIN(PIN_PA24, 0, 0)
+#define PIN_PA24__G0_TXCK PINMUX_PIN(PIN_PA24, 1, 1)
+#define PIN_PA24__FLEXCOM4_IO4 PINMUX_PIN(PIN_PA24, 2, 1)
+#define PIN_PA24__ISC_HSYNC PINMUX_PIN(PIN_PA24, 3, 1)
+#define PIN_PA24__A10 PINMUX_PIN(PIN_PA24, 4, 1)
+#define PIN_PA24__FLEXCOM0_IO5 PINMUX_PIN(PIN_PA24, 5, 1)
+#define PIN_PA25 25
+#define PIN_PA25__GPIO PINMUX_PIN(PIN_PA25, 0, 0)
+#define PIN_PA25__G0_125CK PINMUX_PIN(PIN_PA25, 1, 1)
+#define PIN_PA25__FLEXCOM5_IO4 PINMUX_PIN(PIN_PA25, 2, 1)
+#define PIN_PA25__ISC_VSYNC PINMUX_PIN(PIN_PA25, 3, 1)
+#define PIN_PA25__A11 PINMUX_PIN(PIN_PA25, 4, 1)
+#define PIN_PA25__FLEXCOM0_IO6 PINMUX_PIN(PIN_PA25, 5, 1)
+#define PIN_PA25__FLEXCOM7_IO0 PINMUX_PIN(PIN_PA25, 6, 3)
+#define PIN_PA26 26
+#define PIN_PA26__GPIO PINMUX_PIN(PIN_PA26, 0, 0)
+#define PIN_PA26__G0_TX2 PINMUX_PIN(PIN_PA26, 1, 1)
+#define PIN_PA26__FLEXCOM5_IO2 PINMUX_PIN(PIN_PA26, 2, 1)
+#define PIN_PA26__ISC_FIELD PINMUX_PIN(PIN_PA26, 3, 1)
+#define PIN_PA26__A12 PINMUX_PIN(PIN_PA26, 4, 1)
+#define PIN_PA26__TF0 PINMUX_PIN(PIN_PA26, 5, 1)
+#define PIN_PA26__FLEXCOM7_IO1 PINMUX_PIN(PIN_PA26, 6, 3)
+#define PIN_PA27 27
+#define PIN_PA27__GPIO PINMUX_PIN(PIN_PA27, 0, 0)
+#define PIN_PA27__G0_TX3 PINMUX_PIN(PIN_PA27, 1, 1)
+#define PIN_PA27__FLEXCOM5_IO3 PINMUX_PIN(PIN_PA27, 2, 1)
+#define PIN_PA27__ISC_PCK PINMUX_PIN(PIN_PA27, 3, 1)
+#define PIN_PA27__A13 PINMUX_PIN(PIN_PA27, 4, 1)
+#define PIN_PA27__TK0 PINMUX_PIN(PIN_PA27, 5, 1)
+#define PIN_PA27__FLEXCOM8_IO0 PINMUX_PIN(PIN_PA27, 6, 3)
+#define PIN_PA28 28
+#define PIN_PA28__GPIO PINMUX_PIN(PIN_PA28, 0, 0)
+#define PIN_PA28__G0_RX2 PINMUX_PIN(PIN_PA28, 1, 1)
+#define PIN_PA28__FLEXCOM5_IO0 PINMUX_PIN(PIN_PA28, 2, 1)
+#define PIN_PA28__ISC_D8 PINMUX_PIN(PIN_PA28, 3, 1)
+#define PIN_PA28__A14 PINMUX_PIN(PIN_PA28, 4, 1)
+#define PIN_PA28__RD0 PINMUX_PIN(PIN_PA28, 5, 1)
+#define PIN_PA28__FLEXCOM8_IO1 PINMUX_PIN(PIN_PA28, 6, 3)
+#define PIN_PA29 29
+#define PIN_PA29__GPIO PINMUX_PIN(PIN_PA29, 0, 0)
+#define PIN_PA29__G0_RX3 PINMUX_PIN(PIN_PA29, 1, 1)
+#define PIN_PA29__FLEXCOM5_IO1 PINMUX_PIN(PIN_PA29, 2, 1)
+#define PIN_PA29__ISC_D9 PINMUX_PIN(PIN_PA29, 3, 1)
+#define PIN_PA29__A15 PINMUX_PIN(PIN_PA29, 4, 1)
+#define PIN_PA29__RF0 PINMUX_PIN(PIN_PA29, 5, 1)
+#define PIN_PA29__FLEXCOM9_IO0 PINMUX_PIN(PIN_PA29, 6, 3)
+#define PIN_PA30 30
+#define PIN_PA30__GPIO PINMUX_PIN(PIN_PA30, 0, 0)
+#define PIN_PA30__G0_RXCK PINMUX_PIN(PIN_PA30, 1, 1)
+#define PIN_PA30__FLEXCOM6_IO4 PINMUX_PIN(PIN_PA30, 2, 1)
+#define PIN_PA30__ISC_D10 PINMUX_PIN(PIN_PA30, 3, 1)
+#define PIN_PA30__A16 PINMUX_PIN(PIN_PA30, 4, 1)
+#define PIN_PA30__RK0 PINMUX_PIN(PIN_PA30, 5, 1)
+#define PIN_PA30__FLEXCOM9_IO1 PINMUX_PIN(PIN_PA30, 6, 3)
+#define PIN_PA31 31
+#define PIN_PA31__GPIO PINMUX_PIN(PIN_PA31, 0, 0)
+#define PIN_PA31__G0_TXER PINMUX_PIN(PIN_PA31, 1, 1)
+#define PIN_PA31__FLEXCOM6_IO2 PINMUX_PIN(PIN_PA31, 2, 1)
+#define PIN_PA31__ISC_D11 PINMUX_PIN(PIN_PA31, 3, 1)
+#define PIN_PA31__A17 PINMUX_PIN(PIN_PA31, 4, 1)
+#define PIN_PA31__TD0 PINMUX_PIN(PIN_PA31, 5, 1)
+#define PIN_PA31__FLEXCOM10_IO0 PINMUX_PIN(PIN_PA31, 6, 3)
+#define PIN_PB0 32
+#define PIN_PB0__GPIO PINMUX_PIN(PIN_PB0, 0, 0)
+#define PIN_PB0__G0_COL PINMUX_PIN(PIN_PB0, 1, 1)
+#define PIN_PB0__FLEXCOM6_IO3 PINMUX_PIN(PIN_PB0, 2, 2)
+#define PIN_PB0__EXT_IRQ0 PINMUX_PIN(PIN_PB0, 3, 1)
+#define PIN_PB0__A18 PINMUX_PIN(PIN_PB0, 4, 1)
+#define PIN_PB0__SPDIF_RX PINMUX_PIN(PIN_PB0, 5, 2)
+#define PIN_PB0__FLEXCOM10_IO1 PINMUX_PIN(PIN_PB0, 6, 3)
+#define PIN_PB1 33
+#define PIN_PB1__GPIO PINMUX_PIN(PIN_PB1, 0, 0)
+#define PIN_PB1__G0_CRS PINMUX_PIN(PIN_PB1, 1, 1)
+#define PIN_PB1__FLEXCOM6_IO1 PINMUX_PIN(PIN_PB1, 2, 2)
+#define PIN_PB1__EXT_IRQ1 PINMUX_PIN(PIN_PB1, 3, 1)
+#define PIN_PB1__A19 PINMUX_PIN(PIN_PB1, 4, 1)
+#define PIN_PB1__SPDIF_TX PINMUX_PIN(PIN_PB1, 5, 2)
+#define PIN_PB1__FLEXCOM11_IO0 PINMUX_PIN(PIN_PB1, 6, 3)
+#define PIN_PB2 34
+#define PIN_PB2__GPIO PINMUX_PIN(PIN_PB2, 0, 0)
+#define PIN_PB2__G0_TSUCOMP PINMUX_PIN(PIN_PB2, 1, 1)
+#define PIN_PB2__FLEXCOM6_IO0 PINMUX_PIN(PIN_PB2, 2, 1)
+#define PIN_PB2__ADTRG PINMUX_PIN(PIN_PB2, 3, 1)
+#define PIN_PB2__A20 PINMUX_PIN(PIN_PB2, 4, 1)
+#define PIN_PB2__FLEXCOM11_IO0 PINMUX_PIN(PIN_PB2, 6, 3)
+#define PIN_PB3 35
+#define PIN_PB3__GPIO PINMUX_PIN(PIN_PB3, 0, 0)
+#define PIN_PB3__RF1 PINMUX_PIN(PIN_PB3, 1, 1)
+#define PIN_PB3__FLEXCOM11_IO0 PINMUX_PIN(PIN_PB3, 2, 1)
+#define PIN_PB3__PCK2 PINMUX_PIN(PIN_PB3, 3, 2)
+#define PIN_PB3__D8 PINMUX_PIN(PIN_PB3, 4, 1)
+#define PIN_PB4 36
+#define PIN_PB4__GPIO PINMUX_PIN(PIN_PB4, 0, 0)
+#define PIN_PB4__TF1 PINMUX_PIN(PIN_PB4, 1, 1)
+#define PIN_PB4__FLEXCOM11_IO1 PINMUX_PIN(PIN_PB4, 2, 1)
+#define PIN_PB4__PCK3 PINMUX_PIN(PIN_PB4, 3, 2)
+#define PIN_PB4__D9 PINMUX_PIN(PIN_PB4, 4, 1)
+#define PIN_PB5 37
+#define PIN_PB5__GPIO PINMUX_PIN(PIN_PB5, 0, 0)
+#define PIN_PB5__TK1 PINMUX_PIN(PIN_PB5, 1, 1)
+#define PIN_PB5__FLEXCOM11_IO2 PINMUX_PIN(PIN_PB5, 2, 1)
+#define PIN_PB5__PCK4 PINMUX_PIN(PIN_PB5, 3, 2)
+#define PIN_PB5__D10 PINMUX_PIN(PIN_PB5, 4, 1)
+#define PIN_PB6 38
+#define PIN_PB6__GPIO PINMUX_PIN(PIN_PB6, 0, 0)
+#define PIN_PB6__RK1 PINMUX_PIN(PIN_PB6, 1, 1)
+#define PIN_PB6__FLEXCOM11_IO3 PINMUX_PIN(PIN_PB6, 2, 1)
+#define PIN_PB6__PCK5 PINMUX_PIN(PIN_PB6, 3, 2)
+#define PIN_PB6__D11 PINMUX_PIN(PIN_PB6, 4, 1)
+#define PIN_PB7 39
+#define PIN_PB7__GPIO PINMUX_PIN(PIN_PB7, 0, 0)
+#define PIN_PB7__TD1 PINMUX_PIN(PIN_PB7, 1, 1)
+#define PIN_PB7__FLEXCOM11_IO4 PINMUX_PIN(PIN_PB7, 2, 1)
+#define PIN_PB7__FLEXCOM3_IO5 PINMUX_PIN(PIN_PB7, 3, 2)
+#define PIN_PB7__D12 PINMUX_PIN(PIN_PB7, 4, 1)
+#define PIN_PB8 40
+#define PIN_PB8__GPIO PINMUX_PIN(PIN_PB8, 0, 0)
+#define PIN_PB8__RD1 PINMUX_PIN(PIN_PB8, 1, 1)
+#define PIN_PB8__FLEXCOM8_IO0 PINMUX_PIN(PIN_PB8, 2, 1)
+#define PIN_PB8__FLEXCOM3_IO6 PINMUX_PIN(PIN_PB8, 3, 2)
+#define PIN_PB8__D13 PINMUX_PIN(PIN_PB8, 4, 1)
+#define PIN_PB9 41
+#define PIN_PB9__GPIO PINMUX_PIN(PIN_PB9, 0, 0)
+#define PIN_PB9__QSPI0_IO3 PINMUX_PIN(PIN_PB9, 1, 1)
+#define PIN_PB9__FLEXCOM8_IO1 PINMUX_PIN(PIN_PB9, 2, 1)
+#define PIN_PB9__PDMC0_CLK PINMUX_PIN(PIN_PB9, 3, 1)
+#define PIN_PB9__NCS3_NANDCS PINMUX_PIN(PIN_PB9, 4, 1)
+#define PIN_PB9__PWML0 PINMUX_PIN(PIN_PB9, 5, 2)
+#define PIN_PB10 42
+#define PIN_PB10__GPIO PINMUX_PIN(PIN_PB10, 0, 0)
+#define PIN_PB10__QSPI0_IO2 PINMUX_PIN(PIN_PB10, 1, 1)
+#define PIN_PB10__FLEXCOM8_IO2 PINMUX_PIN(PIN_PB10, 2, 1)
+#define PIN_PB10__PDMC0_DS0 PINMUX_PIN(PIN_PB10, 3, 1)
+#define PIN_PB10__NWE_NWR0_NANDWE PINMUX_PIN(PIN_PB10, 4, 1)
+#define PIN_PB10__PWMH0 PINMUX_PIN(PIN_PB10, 5, 2)
+#define PIN_PB11 43
+#define PIN_PB11__GPIO PINMUX_PIN(PIN_PB11, 0, 0)
+#define PIN_PB11__QSPI0_IO1 PINMUX_PIN(PIN_PB11, 1, 1)
+#define PIN_PB11__FLEXCOM8_IO3 PINMUX_PIN(PIN_PB11, 2, 1)
+#define PIN_PB11__PDMC0_DS1 PINMUX_PIN(PIN_PB11, 3, 1)
+#define PIN_PB11__NRD_NANDOE PINMUX_PIN(PIN_PB11, 4, 1)
+#define PIN_PB11__PWML1 PINMUX_PIN(PIN_PB11, 5, 2)
+#define PIN_PB12 44
+#define PIN_PB12__GPIO PINMUX_PIN(PIN_PB12, 0, 0)
+#define PIN_PB12__QSPI0_IO0 PINMUX_PIN(PIN_PB12, 1, 1)
+#define PIN_PB12__FLEXCOM8_IO4 PINMUX_PIN(PIN_PB12, 2, 1)
+#define PIN_PB12__FLEXCOM6_IO5 PINMUX_PIN(PIN_PB12, 3, 1)
+#define PIN_PB12__A21_NANDALE PINMUX_PIN(PIN_PB12, 4, 1)
+#define PIN_PB12__PWMH1 PINMUX_PIN(PIN_PB12, 5, 2)
+#define PIN_PB13 45
+#define PIN_PB13__GPIO PINMUX_PIN(PIN_PB13, 0, 0)
+#define PIN_PB13__QSPI0_CS PINMUX_PIN(PIN_PB13, 1, 1)
+#define PIN_PB13__FLEXCOM9_IO0 PINMUX_PIN(PIN_PB13, 2, 1)
+#define PIN_PB13__FLEXCOM6_IO6 PINMUX_PIN(PIN_PB13, 3, 1)
+#define PIN_PB13__A22_NANDCLE PINMUX_PIN(PIN_PB13, 4, 1)
+#define PIN_PB13__PWML2 PINMUX_PIN(PIN_PB13, 5, 2)
+#define PIN_PB14 46
+#define PIN_PB14__GPIO PINMUX_PIN(PIN_PB14, 0, 0)
+#define PIN_PB14__QSPI0_SCK PINMUX_PIN(PIN_PB14, 1, 1)
+#define PIN_PB14__FLEXCOM9_IO1 PINMUX_PIN(PIN_PB14, 2, 1)
+#define PIN_PB14__D0 PINMUX_PIN(PIN_PB14, 4, 1)
+#define PIN_PB14__PWMH2 PINMUX_PIN(PIN_PB14, 5, 2)
+#define PIN_PB15 47
+#define PIN_PB15__GPIO PINMUX_PIN(PIN_PB15, 0, 0)
+#define PIN_PB15__QSPI0_SCKN PINMUX_PIN(PIN_PB15, 1, 1)
+#define PIN_PB15__FLEXCOM9_IO2 PINMUX_PIN(PIN_PB15, 2, 1)
+#define PIN_PB15__D1 PINMUX_PIN(PIN_PB15, 4, 1)
+#define PIN_PB15__PWML3 PINMUX_PIN(PIN_PB15, 5, 2)
+#define PIN_PB16 48
+#define PIN_PB16__GPIO PINMUX_PIN(PIN_PB16, 0, 0)
+#define PIN_PB16__QSPI0_IO4 PINMUX_PIN(PIN_PB16, 1, 1)
+#define PIN_PB16__FLEXCOM9_IO3 PINMUX_PIN(PIN_PB16, 2, 1)
+#define PIN_PB16__PCK0 PINMUX_PIN(PIN_PB16, 3, 1)
+#define PIN_PB16__D2 PINMUX_PIN(PIN_PB16, 4, 1)
+#define PIN_PB16__PWMH3 PINMUX_PIN(PIN_PB16, 5, 2)
+#define PIN_PB16__EXT_IRQ0 PINMUX_PIN(PIN_PB16, 6, 2)
+#define PIN_PB17 49
+#define PIN_PB17__GPIO PINMUX_PIN(PIN_PB17, 0, 0)
+#define PIN_PB17__QSPI0_IO5 PINMUX_PIN(PIN_PB17, 1, 1)
+#define PIN_PB17__FLEXCOM9_IO4 PINMUX_PIN(PIN_PB17, 2, 1)
+#define PIN_PB17__PCK1 PINMUX_PIN(PIN_PB17, 3, 1)
+#define PIN_PB17__D3 PINMUX_PIN(PIN_PB17, 4, 1)
+#define PIN_PB17__PWMEXTRG0 PINMUX_PIN(PIN_PB17, 5, 2)
+#define PIN_PB17__EXT_IRQ1 PINMUX_PIN(PIN_PB17, 6, 2)
+#define PIN_PB18 50
+#define PIN_PB18__GPIO PINMUX_PIN(PIN_PB18, 0, 0)
+#define PIN_PB18__QSPI0_IO6 PINMUX_PIN(PIN_PB18, 1, 1)
+#define PIN_PB18__FLEXCOM10_IO0 PINMUX_PIN(PIN_PB18, 2, 1)
+#define PIN_PB18__PCK2 PINMUX_PIN(PIN_PB18, 3, 1)
+#define PIN_PB18__D4 PINMUX_PIN(PIN_PB18, 4, 1)
+#define PIN_PB18__PWMEXTRG1 PINMUX_PIN(PIN_PB18, 5, 2)
+#define PIN_PB19 51
+#define PIN_PB19__GPIO PINMUX_PIN(PIN_PB19, 0, 0)
+#define PIN_PB19__QSPI0_IO7 PINMUX_PIN(PIN_PB19, 1, 1)
+#define PIN_PB19__FLEXCOM10_IO1 PINMUX_PIN(PIN_PB19, 2, 1)
+#define PIN_PB19__PCK3 PINMUX_PIN(PIN_PB19, 3, 1)
+#define PIN_PB19__D5 PINMUX_PIN(PIN_PB19, 4, 1)
+#define PIN_PB19__PWMFI0 PINMUX_PIN(PIN_PB19, 5, 2)
+#define PIN_PB20 52
+#define PIN_PB20__GPIO PINMUX_PIN(PIN_PB20, 0, 0)
+#define PIN_PB20__QSPI0_DQS PINMUX_PIN(PIN_PB20, 1, 1)
+#define PIN_PB20__FLEXCOM10_IO2 PINMUX_PIN(PIN_PB20, 2, 1)
+#define PIN_PB20__D6 PINMUX_PIN(PIN_PB20, 4, 1)
+#define PIN_PB20__PWMFI1 PINMUX_PIN(PIN_PB20, 5, 2)
+#define PIN_PB21 53
+#define PIN_PB21__GPIO PINMUX_PIN(PIN_PB21, 0, 0)
+#define PIN_PB21__QSPI0_INT PINMUX_PIN(PIN_PB21, 1, 1)
+#define PIN_PB21__FLEXCOM10_IO3 PINMUX_PIN(PIN_PB21, 2, 1)
+#define PIN_PB21__FLEXCOM9_IO5 PINMUX_PIN(PIN_PB21, 3, 1)
+#define PIN_PB21__D7 PINMUX_PIN(PIN_PB21, 4, 1)
+#define PIN_PB22 54
+#define PIN_PB22__GPIO PINMUX_PIN(PIN_PB22, 0, 0)
+#define PIN_PB22__QSPI1_IO3 PINMUX_PIN(PIN_PB22, 1, 1)
+#define PIN_PB22__FLEXCOM10_IO4 PINMUX_PIN(PIN_PB22, 2, 1)
+#define PIN_PB22__FLEXCOM9_IO6 PINMUX_PIN(PIN_PB22, 3, 1)
+#define PIN_PB22__NANDRDY PINMUX_PIN(PIN_PB22, 4, 1)
+#define PIN_PB23 55
+#define PIN_PB23__GPIO PINMUX_PIN(PIN_PB23, 0, 0)
+#define PIN_PB23__QSPI1_IO2 PINMUX_PIN(PIN_PB23, 1, 1)
+#define PIN_PB23__FLEXCOM7_IO0 PINMUX_PIN(PIN_PB23, 2, 1)
+#define PIN_PB23__I2SMCC0_CK PINMUX_PIN(PIN_PB23, 3, 1)
+#define PIN_PB23__PCK4 PINMUX_PIN(PIN_PB23, 6, 1)
+#define PIN_PB24 56
+#define PIN_PB24__GPIO PINMUX_PIN(PIN_PB24, 0, 0)
+#define PIN_PB24__QSPI1_IO1 PINMUX_PIN(PIN_PB24, 1, 1)
+#define PIN_PB24__FLEXCOM7_IO1 PINMUX_PIN(PIN_PB24, 2, 1)
+#define PIN_PB24__I2SMCC0_WS PINMUX_PIN(PIN_PB24, 3, 1)
+#define PIN_PB24__PCK5 PINMUX_PIN(PIN_PB24, 6, 1)
+#define PIN_PB25 57
+#define PIN_PB25__GPIO PINMUX_PIN(PIN_PB25, 0, 0)
+#define PIN_PB25__QSPI1_IO0 PINMUX_PIN(PIN_PB25, 1, 1)
+#define PIN_PB25__FLEXCOM7_IO2 PINMUX_PIN(PIN_PB25, 2, 1)
+#define PIN_PB25__I2SMCC0_DOUT1 PINMUX_PIN(PIN_PB25, 3, 1)
+#define PIN_PB25__PCK6 PINMUX_PIN(PIN_PB25, 6, 1)
+#define PIN_PB26 58
+#define PIN_PB26__GPIO PINMUX_PIN(PIN_PB26, 0, 0)
+#define PIN_PB26__QSPI1_CS PINMUX_PIN(PIN_PB26, 1, 1)
+#define PIN_PB26__FLEXCOM7_IO3 PINMUX_PIN(PIN_PB26, 2, 1)
+#define PIN_PB26__I2SMCC0_DOUT0 PINMUX_PIN(PIN_PB26, 3, 1)
+#define PIN_PB26__PWMEXTRG0 PINMUX_PIN(PIN_PB26, 5, 1)
+#define PIN_PB26__PCK7 PINMUX_PIN(PIN_PB26, 6, 1)
+#define PIN_PB27 59
+#define PIN_PB27__GPIO PINMUX_PIN(PIN_PB27, 0, 0)
+#define PIN_PB27__QSPI1_SCK PINMUX_PIN(PIN_PB27, 1, 1)
+#define PIN_PB27__FLEXCOM7_IO4 PINMUX_PIN(PIN_PB27, 2, 1)
+#define PIN_PB27__I2SMCC0_MCK PINMUX_PIN(PIN_PB27, 3, 1)
+#define PIN_PB27__PWMEXTRG1 PINMUX_PIN(PIN_PB27, 5, 1)
+#define PIN_PB28 60
+#define PIN_PB28__GPIO PINMUX_PIN(PIN_PB28, 0, 0)
+#define PIN_PB28__SDMMC1_RSTN PINMUX_PIN(PIN_PB28, 1, 1)
+#define PIN_PB28__ADTRG PINMUX_PIN(PIN_PB28, 2, 2)
+#define PIN_PB28__PWMFI0 PINMUX_PIN(PIN_PB28, 5, 1)
+#define PIN_PB28__FLEXCOM7_IO0 PINMUX_PIN(PIN_PB28, 6, 4)
+#define PIN_PB29 61
+#define PIN_PB29__GPIO PINMUX_PIN(PIN_PB29, 0, 0)
+#define PIN_PB29__SDMMC1_CMD PINMUX_PIN(PIN_PB29, 1, 1)
+#define PIN_PB29__FLEXCOM3_IO2 PINMUX_PIN(PIN_PB29, 2, 2)
+#define PIN_PB29__FLEXCOM0_IO5 PINMUX_PIN(PIN_PB29, 3, 2)
+#define PIN_PB29__TIOA3 PINMUX_PIN(PIN_PB29, 4, 2)
+#define PIN_PB29__PWMFI1 PINMUX_PIN(PIN_PB29, 5, 1)
+#define PIN_PB29__FLEXCOM7_IO1 PINMUX_PIN(PIN_PB29, 6, 4)
+#define PIN_PB30 62
+#define PIN_PB30__GPIO PINMUX_PIN(PIN_PB30, 0, 0)
+#define PIN_PB30__SDMMC1_CK PINMUX_PIN(PIN_PB30, 1, 1)
+#define PIN_PB30__FLEXCOM3_IO3 PINMUX_PIN(PIN_PB30, 2, 2)
+#define PIN_PB30__FLEXCOM0_IO6 PINMUX_PIN(PIN_PB30, 3, 2)
+#define PIN_PB30__TIOB3 PINMUX_PIN(PIN_PB30, 4, 1)
+#define PIN_PB30__PWMH0 PINMUX_PIN(PIN_PB30, 5, 1)
+#define PIN_PB30__FLEXCOM8_IO0 PINMUX_PIN(PIN_PB30, 6, 4)
+#define PIN_PB31 63
+#define PIN_PB31__GPIO PINMUX_PIN(PIN_PB31, 0, 0)
+#define PIN_PB31__SDMMC1_DAT0 PINMUX_PIN(PIN_PB31, 1, 1)
+#define PIN_PB31__FLEXCOM3_IO4 PINMUX_PIN(PIN_PB31, 2, 2)
+#define PIN_PB31__FLEXCOM9_IO5 PINMUX_PIN(PIN_PB31, 3, 2)
+#define PIN_PB31__TCLK3 PINMUX_PIN(PIN_PB31, 4, 1)
+#define PIN_PB31__PWML0 PINMUX_PIN(PIN_PB31, 5, 1)
+#define PIN_PB31__FLEXCOM8_IO1 PINMUX_PIN(PIN_PB31, 6, 4)
+#define PIN_PC0 64
+#define PIN_PC0__GPIO PINMUX_PIN(PIN_PC0, 0, 0)
+#define PIN_PC0__SDMMC1_DAT1 PINMUX_PIN(PIN_PC0, 1, 1)
+#define PIN_PC0__FLEXCOM3_IO0 PINMUX_PIN(PIN_PC0, 2, 2)
+#define PIN_PC0__TIOA4 PINMUX_PIN(PIN_PC0, 4, 1)
+#define PIN_PC0__PWML1 PINMUX_PIN(PIN_PC0, 5, 1)
+#define PIN_PC0__FLEXCOM9_IO0 PINMUX_PIN(PIN_PC0, 6, 4)
+#define PIN_PC1 65
+#define PIN_PC1__GPIO PINMUX_PIN(PIN_PC1, 0, 0)
+#define PIN_PC1__SDMMC1_DAT2 PINMUX_PIN(PIN_PC1, 1, 1)
+#define PIN_PC1__FLEXCOM3_IO1 PINMUX_PIN(PIN_PC1, 2, 2)
+#define PIN_PC1__TIOB4 PINMUX_PIN(PIN_PC1, 4, 1)
+#define PIN_PC1__PWMH1 PINMUX_PIN(PIN_PC1, 5, 1)
+#define PIN_PC1__FLEXCOM9_IO1 PINMUX_PIN(PIN_PC1, 6, 4)
+#define PIN_PC2 66
+#define PIN_PC2__GPIO PINMUX_PIN(PIN_PC2, 0, 0)
+#define PIN_PC2__SDMMC1_DAT3 PINMUX_PIN(PIN_PC2, 1, 1)
+#define PIN_PC2__FLEXCOM4_IO0 PINMUX_PIN(PIN_PC2, 2, 2)
+#define PIN_PC2__TCLK4 PINMUX_PIN(PIN_PC2, 4, 1)
+#define PIN_PC2__PWML2 PINMUX_PIN(PIN_PC2, 5, 1)
+#define PIN_PC2__FLEXCOM10_IO0 PINMUX_PIN(PIN_PC2, 6, 4)
+#define PIN_PC3 67
+#define PIN_PC3__GPIO PINMUX_PIN(PIN_PC3, 0, 0)
+#define PIN_PC3__SDMMC1_WP PINMUX_PIN(PIN_PC3, 1, 1)
+#define PIN_PC3__FLEXCOM4_IO1 PINMUX_PIN(PIN_PC3, 2, 2)
+#define PIN_PC3__TIOA5 PINMUX_PIN(PIN_PC3, 4, 1)
+#define PIN_PC3__PWMH2 PINMUX_PIN(PIN_PC3, 5, 1)
+#define PIN_PC3__FLEXCOM10_IO1 PINMUX_PIN(PIN_PC3, 6, 4)
+#define PIN_PC4 68
+#define PIN_PC4__GPIO PINMUX_PIN(PIN_PC4, 0, 0)
+#define PIN_PC4__SDMMC1_CD PINMUX_PIN(PIN_PC4, 1, 1)
+#define PIN_PC4__FLEXCOM4_IO2 PINMUX_PIN(PIN_PC4, 2, 2)
+#define PIN_PC4__FLEXCOM9_IO6 PINMUX_PIN(PIN_PC4, 3, 2)
+#define PIN_PC4__TIOB5 PINMUX_PIN(PIN_PC4, 4, 1)
+#define PIN_PC4__PWML3 PINMUX_PIN(PIN_PC4, 5, 1)
+#define PIN_PC4__FLEXCOM11_IO0 PINMUX_PIN(PIN_PC4, 6, 4)
+#define PIN_PC5 69
+#define PIN_PC5__GPIO PINMUX_PIN(PIN_PC5, 0, 0)
+#define PIN_PC5__SDMMC1_1V8SEL PINMUX_PIN(PIN_PC5, 1, 1)
+#define PIN_PC5__FLEXCOM4_IO3 PINMUX_PIN(PIN_PC5, 2, 2)
+#define PIN_PC5__FLEXCOM6_IO5 PINMUX_PIN(PIN_PC5, 3, 2)
+#define PIN_PC5__TCLK5 PINMUX_PIN(PIN_PC5, 4, 1)
+#define PIN_PC5__PWMH3 PINMUX_PIN(PIN_PC5, 5, 1)
+#define PIN_PC5__FLEXCOM11_IO1 PINMUX_PIN(PIN_PC5, 6, 4)
+#define PIN_PC6 70
+#define PIN_PC6__GPIO PINMUX_PIN(PIN_PC6, 0, 0)
+#define PIN_PC6__FLEXCOM4_IO4 PINMUX_PIN(PIN_PC6, 2, 2)
+#define PIN_PC6__FLEXCOM6_IO6 PINMUX_PIN(PIN_PC6, 3, 2)
+#define PIN_PC7 71
+#define PIN_PC7__GPIO PINMUX_PIN(PIN_PC7, 0, 0)
+#define PIN_PC7__I2SMCC0_DIN0 PINMUX_PIN(PIN_PC7, 1, 1)
+#define PIN_PC7__FLEXCOM7_IO0 PINMUX_PIN(PIN_PC7, 2, 2)
+#define PIN_PC8 72
+#define PIN_PC8__GPIO PINMUX_PIN(PIN_PC8, 0, 0)
+#define PIN_PC8__I2SMCC0_DIN1 PINMUX_PIN(PIN_PC8, 1, 1)
+#define PIN_PC8__FLEXCOM7_IO1 PINMUX_PIN(PIN_PC8, 2, 2)
+#define PIN_PC9 73
+#define PIN_PC9__GPIO PINMUX_PIN(PIN_PC9, 0, 0)
+#define PIN_PC9__I2SMCC0_DOUT3 PINMUX_PIN(PIN_PC9, 1, 1)
+#define PIN_PC9__FLEXCOM7_IO2 PINMUX_PIN(PIN_PC9, 2, 2)
+#define PIN_PC9__FLEXCOM1_IO0 PINMUX_PIN(PIN_PC9, 6, 4)
+#define PIN_PC10 74
+#define PIN_PC10__GPIO PINMUX_PIN(PIN_PC10, 0, 0)
+#define PIN_PC10__I2SMCC0_DOUT2 PINMUX_PIN(PIN_PC10, 1, 1)
+#define PIN_PC10__FLEXCOM7_IO3 PINMUX_PIN(PIN_PC10, 2, 2)
+#define PIN_PC10__FLEXCOM1_IO1 PINMUX_PIN(PIN_PC10, 6, 4)
+#define PIN_PC11 75
+#define PIN_PC11__GPIO PINMUX_PIN(PIN_PC11, 0, 0)
+#define PIN_PC11__I2SMCC1_CK PINMUX_PIN(PIN_PC11, 1, 1)
+#define PIN_PC11__FLEXCOM7_IO4 PINMUX_PIN(PIN_PC11, 2, 2)
+#define PIN_PC11__FLEXCOM2_IO0 PINMUX_PIN(PIN_PC11, 6, 4)
+#define PIN_PC12 76
+#define PIN_PC12__GPIO PINMUX_PIN(PIN_PC12, 0, 0)
+#define PIN_PC12__I2SMCC1_WS PINMUX_PIN(PIN_PC12, 1, 1)
+#define PIN_PC12__FLEXCOM8_IO2 PINMUX_PIN(PIN_PC12, 2, 2)
+#define PIN_PC12__FLEXCOM2_IO1 PINMUX_PIN(PIN_PC12, 6, 4)
+#define PIN_PC13 77
+#define PIN_PC13__GPIO PINMUX_PIN(PIN_PC13, 0, 0)
+#define PIN_PC13__I2SMCC1_MCK PINMUX_PIN(PIN_PC13, 1, 1)
+#define PIN_PC13__FLEXCOM8_IO1 PINMUX_PIN(PIN_PC13, 2, 2)
+#define PIN_PC13__FLEXCOM3_IO0 PINMUX_PIN(PIN_PC13, 6, 4)
+#define PIN_PC14 78
+#define PIN_PC14__GPIO PINMUX_PIN(PIN_PC14, 0, 0)
+#define PIN_PC14__I2SMCC1_DOUT0 PINMUX_PIN(PIN_PC14, 1, 1)
+#define PIN_PC14__FLEXCOM8_IO0 PINMUX_PIN(PIN_PC14, 2, 2)
+#define PIN_PC14__FLEXCOM3_IO1 PINMUX_PIN(PIN_PC14, 6, 4)
+#define PIN_PC15 79
+#define PIN_PC15__GPIO PINMUX_PIN(PIN_PC15, 0, 0)
+#define PIN_PC15__I2SMCC1_DOUT1 PINMUX_PIN(PIN_PC15, 1, 1)
+#define PIN_PC15__FLEXCOM8_IO3 PINMUX_PIN(PIN_PC15, 2, 2)
+#define PIN_PC15__FLEXCOM4_IO0 PINMUX_PIN(PIN_PC15, 6, 4)
+#define PIN_PC16 80
+#define PIN_PC16__GPIO PINMUX_PIN(PIN_PC16, 0, 0)
+#define PIN_PC16__I2SMCC_DOUT2 PINMUX_PIN(PIN_PC16, 1, 1)
+#define PIN_PC16__FLEXCOM8_IO4 PINMUX_PIN(PIN_PC16, 2, 2)
+#define PIN_PC16__FLEXCOM3_IO1 PINMUX_PIN(PIN_PC16, 6, 4)
+#define PIN_PC17 81
+#define PIN_PC17__GPIO PINMUX_PIN(PIN_PC17, 0, 0)
+#define PIN_PC17__I2SMCC1_DOUT3 PINMUX_PIN(PIN_PC17, 1, 1)
+#define PIN_PC17__EXT_IRQ0 PINMUX_PIN(PIN_PC17, 2, 3)
+#define PIN_PC17__FLEXCOM5_IO0 PINMUX_PIN(PIN_PC17, 6, 4)
+#define PIN_PC18 82
+#define PIN_PC18__GPIO PINMUX_PIN(PIN_PC18, 0, 0)
+#define PIN_PC18__I2SMCC1_DIN0 PINMUX_PIN(PIN_PC18, 1, 1)
+#define PIN_PC18__FLEXCOM9_IO0 PINMUX_PIN(PIN_PC18, 2, 2)
+#define PIN_PC18__FLEXCOM5_IO1 PINMUX_PIN(PIN_PC18, 6, 4)
+#define PIN_PC19 83
+#define PIN_PC19__GPIO PINMUX_PIN(PIN_PC19, 0, 0)
+#define PIN_PC19__I2SMCC1_DIN1 PINMUX_PIN(PIN_PC19, 1, 1)
+#define PIN_PC19__FLEXCOM9_IO1 PINMUX_PIN(PIN_PC19, 2, 2)
+#define PIN_PC19__FLEXCOM6_IO0 PINMUX_PIN(PIN_PC19, 6, 4)
+#define PIN_PC20 84
+#define PIN_PC20__GPIO PINMUX_PIN(PIN_PC20, 0, 0)
+#define PIN_PC20__I2SMCC1_DIN2 PINMUX_PIN(PIN_PC20, 1, 1)
+#define PIN_PC20__FLEXCOM9_IO4 PINMUX_PIN(PIN_PC20, 2, 2)
+#define PIN_PC20__FLEXCOM6_IO1 PINMUX_PIN(PIN_PC20, 6, 4)
+#define PIN_PC21 85
+#define PIN_PC21__GPIO PINMUX_PIN(PIN_PC21, 0, 0)
+#define PIN_PC21__I2SMCC1_DIN3 PINMUX_PIN(PIN_PC21, 1, 1)
+#define PIN_PC21__FLEXCOM9_IO2 PINMUX_PIN(PIN_PC21, 2, 2)
+#define PIN_PC21__D3 PINMUX_PIN(PIN_PC21, 4, 2)
+#define PIN_PC21__FLEXCOM6_IO0 PINMUX_PIN(PIN_PC21, 6, 5)
+#define PIN_PC22 86
+#define PIN_PC22__GPIO PINMUX_PIN(PIN_PC22, 0, 0)
+#define PIN_PC22__I2SMCC0_DIN2 PINMUX_PIN(PIN_PC22, 1, 1)
+#define PIN_PC22__FLEXCOM9_IO3 PINMUX_PIN(PIN_PC22, 2, 2)
+#define PIN_PC22__D4 PINMUX_PIN(PIN_PC22, 4, 2)
+#define PIN_PC22__FLEXCOM6_IO1 PINMUX_PIN(PIN_PC22, 6, 5)
+#define PIN_PC23 87
+#define PIN_PC23__GPIO PINMUX_PIN(PIN_PC23, 0, 0)
+#define PIN_PC23__I2SMCC0_DIN3 PINMUX_PIN(PIN_PC23, 1, 1)
+#define PIN_PC23__FLEXCOM0_IO5 PINMUX_PIN(PIN_PC23, 2, 3)
+#define PIN_PC23__D5 PINMUX_PIN(PIN_PC23, 4, 2)
+#define PIN_PC23__FLEXCOM7_IO0 PINMUX_PIN(PIN_PC23, 6, 5)
+#define PIN_PC24 88
+#define PIN_PC24__GPIO PINMUX_PIN(PIN_PC24, 0, 0)
+#define PIN_PC24__FLEXCOM0_IO6 PINMUX_PIN(PIN_PC24, 2, 3)
+#define PIN_PC24__EXT_IRQ1 PINMUX_PIN(PIN_PC24, 3, 3)
+#define PIN_PC24__D6 PINMUX_PIN(PIN_PC24, 4, 2)
+#define PIN_PC24__FLEXCOM7_IO1 PINMUX_PIN(PIN_PC24, 6, 5)
+#define PIN_PC25 89
+#define PIN_PC25__GPIO PINMUX_PIN(PIN_PC25, 0, 0)
+#define PIN_PC25__NTRST PINMUX_PIN(PIN_PC25, 1, 1)
+#define PIN_PC26 90
+#define PIN_PC26__GPIO PINMUX_PIN(PIN_PC26, 0, 0)
+#define PIN_PC26__TCK_SWCLK PINMUX_PIN(PIN_PC26, 1, 1)
+#define PIN_PC27 91
+#define PIN_PC27__GPIO PINMUX_PIN(PIN_PC27, 0, 0)
+#define PIN_PC27__TMS_SWDIO PINMUX_PIN(PIN_PC27, 1, 1)
+#define PIN_PC28 92
+#define PIN_PC28__GPIO PINMUX_PIN(PIN_PC28, 0, 0)
+#define PIN_PC28__TDI PINMUX_PIN(PIN_PC28, 1, 1)
+#define PIN_PC29 93
+#define PIN_PC29__GPIO PINMUX_PIN(PIN_PC29, 0, 0)
+#define PIN_PC29__TDO PINMUX_PIN(PIN_PC29, 1, 1)
+#define PIN_PC30 94
+#define PIN_PC30__GPIO PINMUX_PIN(PIN_PC30, 0, 0)
+#define PIN_PC30__FLEXCOM10_IO0 PINMUX_PIN(PIN_PC30, 2, 2)
+#define PIN_PC31 95
+#define PIN_PC31__GPIO PINMUX_PIN(PIN_PC31, 0, 0)
+#define PIN_PC31__FLEXCOM10_IO1 PINMUX_PIN(PIN_PC31, 2, 2)
+#define PIN_PD0 96
+#define PIN_PD0__GPIO PINMUX_PIN(PIN_PD0, 0, 0)
+#define PIN_PD0__FLEXCOM11_IO0 PINMUX_PIN(PIN_PD0, 2, 2)
+#define PIN_PD1 97
+#define PIN_PD1__GPIO PINMUX_PIN(PIN_PD1, 0, 0)
+#define PIN_PD1__FLEXCOM11_IO1 PINMUX_PIN(PIN_PD1, 2, 2)
+#define PIN_PD2 98
+#define PIN_PD2__GPIO PINMUX_PIN(PIN_PD2, 0, 0)
+#define PIN_PD2__SDMMC2_RSTN PINMUX_PIN(PIN_PD2, 1, 1)
+#define PIN_PD2__PCK0 PINMUX_PIN(PIN_PD2, 2, 2)
+#define PIN_PD2__CANTX4 PINMUX_PIN(PIN_PD2, 3, 1)
+#define PIN_PD2__D7 PINMUX_PIN(PIN_PD2, 4, 2)
+#define PIN_PD2__TIOA0 PINMUX_PIN(PIN_PD2, 5, 2)
+#define PIN_PD2__FLEXCOM8_IO0 PINMUX_PIN(PIN_PD2, 6, 5)
+#define PIN_PD3 99
+#define PIN_PD3__GPIO PINMUX_PIN(PIN_PD3, 0, 0)
+#define PIN_PD3__SDMMC2_CMD PINMUX_PIN(PIN_PD3, 1, 1)
+#define PIN_PD3__FLEXCOM0_IO0 PINMUX_PIN(PIN_PD3, 2, 2)
+#define PIN_PD3__CANRX4 PINMUX_PIN(PIN_PD3, 3, 1)
+#define PIN_PD3__NANDRDY PINMUX_PIN(PIN_PD3, 4, 2)
+#define PIN_PD3__TIOB0 PINMUX_PIN(PIN_PD3, 5, 2)
+#define PIN_PD3__FLEXCOM8_IO1 PINMUX_PIN(PIN_PD3, 6, 5)
+#define PIN_PD4 100
+#define PIN_PD4__GPIO PINMUX_PIN(PIN_PD4, 0, 0)
+#define PIN_PD4__SDMMC2_CK PINMUX_PIN(PIN_PD4, 1, 1)
+#define PIN_PD4__FLEXCOM0_IO1 PINMUX_PIN(PIN_PD4, 2, 2)
+#define PIN_PD4__CANTX5 PINMUX_PIN(PIN_PD4, 3, 1)
+#define PIN_PD4__NCS3_NANDCS PINMUX_PIN(PIN_PD4, 4, 2)
+#define PIN_PD4__TCLK0 PINMUX_PIN(PIN_PD4, 5, 2)
+#define PIN_PD4__FLEXCOM9_IO0 PINMUX_PIN(PIN_PD4, 6, 5)
+#define PIN_PD5 101
+#define PIN_PD5__GPIO PINMUX_PIN(PIN_PD5, 0, 0)
+#define PIN_PD5__SDMMC2_DAT0 PINMUX_PIN(PIN_PD5, 1, 1)
+#define PIN_PD5__FLEXCOM0_IO2 PINMUX_PIN(PIN_PD5, 2, 2)
+#define PIN_PD5__CANRX5 PINMUX_PIN(PIN_PD5, 3, 1)
+#define PIN_PD5__NWE_NWR0_NANDWE PINMUX_PIN(PIN_PD5, 4, 2)
+#define PIN_PD5__TIOA1 PINMUX_PIN(PIN_PD5, 5, 2)
+#define PIN_PD5__FLEXCOM9_IO1 PINMUX_PIN(PIN_PD5, 6, 5)
+#define PIN_PD6 102
+#define PIN_PD6__GPIO PINMUX_PIN(PIN_PD6, 0, 0)
+#define PIN_PD6__SDMMC2_DAT1 PINMUX_PIN(PIN_PD6, 1, 1)
+#define PIN_PD6__FLEXCOM0_IO3 PINMUX_PIN(PIN_PD6, 2, 2)
+#define PIN_PD6__SPDIF_RX PINMUX_PIN(PIN_PD6, 3, 3)
+#define PIN_PD6__NRD_NANDOE PINMUX_PIN(PIN_PD6, 4, 2)
+#define PIN_PD6__TIOB1 PINMUX_PIN(PIN_PD6, 5, 2)
+#define PIN_PD6__FLEXCOM10_IO0 PINMUX_PIN(PIN_PD6, 6, 5)
+#define PIN_PD7 103
+#define PIN_PD7__GPIO PINMUX_PIN(PIN_PD7, 0, 0)
+#define PIN_PD7__SDMMC2_DAT2 PINMUX_PIN(PIN_PD7, 1, 1)
+#define PIN_PD7__FLEXCOM0_IO4 PINMUX_PIN(PIN_PD7, 2, 2)
+#define PIN_PD7__SPDIF_TX PINMUX_PIN(PIN_PD7, 2, 2)
+#define PIN_PD7__A21_NANDALE PINMUX_PIN(PIN_PD7, 4, 2)
+#define PIN_PD7__TCLK1 PINMUX_PIN(PIN_PD7, 5, 2)
+#define PIN_PD7__FLEXCOM10_IO1 PINMUX_PIN(PIN_PD7, 6, 5)
+#define PIN_PD8 104
+#define PIN_PD8__GPIO PINMUX_PIN(PIN_PD8, 0, 0)
+#define PIN_PD8__SDMMC2_DAT3 PINMUX_PIN(PIN_PD8, 1, 1)
+#define PIN_PD8__I2SMCC0_DIN0 PINMUX_PIN(PIN_PD8, 3, 1)
+#define PIN_PD8__A11_NANDCLE PINMUX_PIN(PIN_PD8, 4, 2)
+#define PIN_PD8__TIOA2 PINMUX_PIN(PIN_PD8, 5, 2)
+#define PIN_PD8__FLEXCOM11_IO0 PINMUX_PIN(PIN_PD8, 6, 5)
+#define PIN_PD9 105
+#define PIN_PD9__GPIO PINMUX_PIN(PIN_PD9, 0, 0)
+#define PIN_PD9__SDMMC2_WP PINMUX_PIN(PIN_PD9, 1, 1)
+#define PIN_PD9__I2SMCC0_DIN1 PINMUX_PIN(PIN_PD9, 3, 2)
+#define PIN_PD9__D0 PINMUX_PIN(PIN_PD9, 4, 2)
+#define PIN_PD9__TIOB2 PINMUX_PIN(PIN_PD9, 5, 2)
+#define PIN_PD9__FLEXCOM11_IO1 PINMUX_PIN(PIN_PD9, 6, 5)
+#define PIN_PD10 106
+#define PIN_PD10__GPIO PINMUX_PIN(PIN_PD10, 0, 0)
+#define PIN_PD10__SDMMC2_CD PINMUX_PIN(PIN_PD10, 1, 1)
+#define PIN_PD10__PCK6 PINMUX_PIN(PIN_PD10, 2, 2)
+#define PIN_PD10__I2SMCC0_DIN2 PINMUX_PIN(PIN_PD10, 3, 2)
+#define PIN_PD10__D1 PINMUX_PIN(PIN_PD10, 4, 2)
+#define PIN_PD10__TCLK2 PINMUX_PIN(PIN_PD10, 5, 2)
+#define PIN_PD10__FLEXCOM0_IO0 PINMUX_PIN(PIN_PD10, 6, 3)
+#define PIN_PD11 107
+#define PIN_PD11__GPIO PINMUX_PIN(PIN_PD11, 0, 0)
+#define PIN_PD11__SDMMC2_1V8SEL PINMUX_PIN(PIN_PD11, 1, 1)
+#define PIN_PD11__PCK7 PINMUX_PIN(PIN_PD11, 2, 2)
+#define PIN_PD11__I2SMCC0_DIN3 PINMUX_PIN(PIN_PD11, 3, 2)
+#define PIN_PD11__D2 PINMUX_PIN(PIN_PD11, 4, 2)
+#define PIN_PD11__TIOA3 PINMUX_PIN(PIN_PD11, 5, 2)
+#define PIN_PD11__FLEXCOM0_IO1 PINMUX_PIN(PIN_PD11, 6, 3)
+#define PIN_PD12 108
+#define PIN_PD12__GPIO PINMUX_PIN(PIN_PD12, 0, 0)
+#define PIN_PD12__PCK1 PINMUX_PIN(PIN_PD12, 1, 2)
+#define PIN_PD12__FLEXCOM1_IO0 PINMUX_PIN(PIN_PD12, 2, 2)
+#define PIN_PD12__CANTX0 PINMUX_PIN(PIN_PD12, 4, 2)
+#define PIN_PD12__TIOB3 PINMUX_PIN(PIN_PD12, 5, 2)
+#define PIN_PD13 109
+#define PIN_PD13__GPIO PINMUX_PIN(PIN_PD13, 0, 0)
+#define PIN_PD13__I2SMCC0_CK PINMUX_PIN(PIN_PD13, 1, 2)
+#define PIN_PD13__FLEXCOM1_IO1 PINMUX_PIN(PIN_PD13, 2, 2)
+#define PIN_PD13__PWML0 PINMUX_PIN(PIN_PD13, 3, 4)
+#define PIN_PD13__CANRX0 PINMUX_PIN(PIN_PD13, 4, 2)
+#define PIN_PD13__TCLK3 PINMUX_PIN(PIN_PD13, 5, 2)
+#define PIN_PD14 110
+#define PIN_PD14__GPIO PINMUX_PIN(PIN_PD14, 0, 0)
+#define PIN_PD14__I2SMCC0_MCK PINMUX_PIN(PIN_PD14, 1, 2)
+#define PIN_PD14__FLEXCOM1_IO2 PINMUX_PIN(PIN_PD14, 2, 2)
+#define PIN_PD14__PWMH0 PINMUX_PIN(PIN_PD14, 3, 4)
+#define PIN_PD14__CANTX1 PINMUX_PIN(PIN_PD14, 4, 2)
+#define PIN_PD14__TIOA4 PINMUX_PIN(PIN_PD14, 5, 2)
+#define PIN_PD14__FLEXCOM2_IO0 PINMUX_PIN(PIN_PD14, 6, 5)
+#define PIN_PD15 111
+#define PIN_PD15__GPIO PINMUX_PIN(PIN_PD15, 0, 0)
+#define PIN_PD15__I2SMCC0_WS PINMUX_PIN(PIN_PD15, 1, 2)
+#define PIN_PD15__FLEXCOM1_IO3 PINMUX_PIN(PIN_PD15, 2, 2)
+#define PIN_PD15__PWML1 PINMUX_PIN(PIN_PD15, 3, 4)
+#define PIN_PD15__CANRX1 PINMUX_PIN(PIN_PD15, 4, 2)
+#define PIN_PD15__TIOB4 PINMUX_PIN(PIN_PD15, 5, 2)
+#define PIN_PD15__FLEXCOM2_IO1 PINMUX_PIN(PIN_PD15, 6, 5)
+#define PIN_PD16 112
+#define PIN_PD16__GPIO PINMUX_PIN(PIN_PD16, 0, 0)
+#define PIN_PD16__I2SMCC0_DOUT0 PINMUX_PIN(PIN_PD16, 1, 2)
+#define PIN_PD16__FLEXCOM1_IO4 PINMUX_PIN(PIN_PD16, 2, 2)
+#define PIN_PD16__PWMH1 PINMUX_PIN(PIN_PD16, 3, 4)
+#define PIN_PD16__CANTX2 PINMUX_PIN(PIN_PD16, 4, 2)
+#define PIN_PD16__TCLK4 PINMUX_PIN(PIN_PD16, 5, 2)
+#define PIN_PD16__FLEXCOM3_IO0 PINMUX_PIN(PIN_PD16, 6, 5)
+#define PIN_PD17 113
+#define PIN_PD17__GPIO PINMUX_PIN(PIN_PD17, 0, 0)
+#define PIN_PD17__I2SMCC0_DOUT1 PINMUX_PIN(PIN_PD17, 1, 2)
+#define PIN_PD17__FLEXCOM2_IO0 PINMUX_PIN(PIN_PD17, 2, 2)
+#define PIN_PD17__PWML2 PINMUX_PIN(PIN_PD17, 3, 4)
+#define PIN_PD17__CANRX2 PINMUX_PIN(PIN_PD17, 4, 2)
+#define PIN_PD17__TIOA5 PINMUX_PIN(PIN_PD17, 5, 2)
+#define PIN_PD17__FLEXCOM3_IO1 PINMUX_PIN(PIN_PD17, 6, 5)
+#define PIN_PD18 114
+#define PIN_PD18__GPIO PINMUX_PIN(PIN_PD18, 0, 0)
+#define PIN_PD18__I2SMCC0_DOUT2 PINMUX_PIN(PIN_PD18, 1, 2)
+#define PIN_PD18__FLEXCOM2_IO1 PINMUX_PIN(PIN_PD18, 2, 2)
+#define PIN_PD18__PWMH2 PINMUX_PIN(PIN_PD18, 3, 4)
+#define PIN_PD18__CANTX3 PINMUX_PIN(PIN_PD18, 4, 2)
+#define PIN_PD18__TIOB5 PINMUX_PIN(PIN_PD18, 5, 2)
+#define PIN_PD18__FLEXCOM4_IO0 PINMUX_PIN(PIN_PD18, 6, 5)
+#define PIN_PD19 115
+#define PIN_PD19__GPIO PINMUX_PIN(PIN_PD19, 0, 0)
+#define PIN_PD19__I2SMCC0_DOUT3 PINMUX_PIN(PIN_PD19, 1, 2)
+#define PIN_PD19__FLEXCOM2_IO2 PINMUX_PIN(PIN_PD19, 2, 2)
+#define PIN_PD19__PWML3 PINMUX_PIN(PIN_PD19, 3, 4)
+#define PIN_PD19__CANRX3 PINMUX_PIN(PIN_PD19, 4, 2)
+#define PIN_PD19__TCLK5 PINMUX_PIN(PIN_PD19, 5, 2)
+#define PIN_PD19__FLEXCOM4_IO1 PINMUX_PIN(PIN_PD19, 6, 5)
+#define PIN_PD20 116
+#define PIN_PD20__GPIO PINMUX_PIN(PIN_PD20, 0, 0)
+#define PIN_PD20__PCK0 PINMUX_PIN(PIN_PD20, 1, 3)
+#define PIN_PD20__FLEXCOM2_IO3 PINMUX_PIN(PIN_PD20, 2, 2)
+#define PIN_PD20__PWMH3 PINMUX_PIN(PIN_PD20, 3, 4)
+#define PIN_PD20__CANTX4 PINMUX_PIN(PIN_PD20, 5, 2)
+#define PIN_PD20__FLEXCOM5_IO0 PINMUX_PIN(PIN_PD20, 6, 5)
+#define PIN_PD21 117
+#define PIN_PD21__GPIO PINMUX_PIN(PIN_PD21, 0, 0)
+#define PIN_PD21__PCK1 PINMUX_PIN(PIN_PD21, 1, 3)
+#define PIN_PD21__FLEXCOM2_IO4 PINMUX_PIN(PIN_PD21, 2, 2)
+#define PIN_PD21__CANRX4 PINMUX_PIN(PIN_PD21, 4, 2)
+#define PIN_PD21__FLEXCOM5_IO1 PINMUX_PIN(PIN_PD21, 6, 5)
+#define PIN_PD21__G1_TXEN PINMUX_PIN(PIN_PD21, 7, 1)
+#define PIN_PD22 118
+#define PIN_PD22__GPIO PINMUX_PIN(PIN_PD22, 0, 0)
+#define PIN_PD22__PDMC0_CLK PINMUX_PIN(PIN_PD22, 1, 2)
+#define PIN_PD22__PWMEXTRG0 PINMUX_PIN(PIN_PD22, 3, 4)
+#define PIN_PD22__RD1 PINMUX_PIN(PIN_PD22, 4, 2)
+#define PIN_PD22__CANTX5 PINMUX_PIN(PIN_PD22, 6, 2)
+#define PIN_PD22__G1_TX0 PINMUX_PIN(PIN_PD22, 7, 1)
+#define PIN_PD23 119
+#define PIN_PD23__GPIO PINMUX_PIN(PIN_PD23, 0, 0)
+#define PIN_PD23__PDMC0_DS0 PINMUX_PIN(PIN_PD23, 1, 2)
+#define PIN_PD23__PWMEXTRG1 PINMUX_PIN(PIN_PD23, 3, 4)
+#define PIN_PD23__RF1 PINMUX_PIN(PIN_PD23, 4, 2)
+#define PIN_PD23__ISC_MCK PINMUX_PIN(PIN_PD23, 5, 2)
+#define PIN_PD23__CANRX5 PINMUX_PIN(PIN_PD23, 6, 2)
+#define PIN_PD23__G1_TX1 PINMUX_PIN(PIN_PD23, 7, 1)
+#define PIN_PD24 120
+#define PIN_PD24__GPIO PINMUX_PIN(PIN_PD24, 0, 0)
+#define PIN_PD24__PDMC0_DS1 PINMUX_PIN(PIN_PD24, 1, 2)
+#define PIN_PD24__PWMFI0 PINMUX_PIN(PIN_PD24, 3, 4)
+#define PIN_PD24__RK1 PINMUX_PIN(PIN_PD24, 4, 2)
+#define PIN_PD24__ISC_D0 PINMUX_PIN(PIN_PD24, 5, 2)
+#define PIN_PD24__G1_RXDV PINMUX_PIN(PIN_PD24, 7, 1)
+#define PIN_PD25 121
+#define PIN_PD25__GPIO PINMUX_PIN(PIN_PD25, 0, 0)
+#define PIN_PD25__PDMC1_CLK PINMUX_PIN(PIN_PD25, 1, 2)
+#define PIN_PD25__FLEXCOM5_IO0 PINMUX_PIN(PIN_PD25, 2, 2)
+#define PIN_PD25__PWMFI1 PINMUX_PIN(PIN_PD25, 3, 4)
+#define PIN_PD25__TD1 PINMUX_PIN(PIN_PD25, 4, 2)
+#define PIN_PD25__ISC_D1 PINMUX_PIN(PIN_PD25, 5, 2)
+#define PIN_PD25__G1_RX0 PINMUX_PIN(PIN_PD25, 7, 1)
+#define PIN_PD26 122
+#define PIN_PD26__GPIO PINMUX_PIN(PIN_PD26, 0, 0)
+#define PIN_PD26__PDMC1_DS0 PINMUX_PIN(PIN_PD26, 1, 2)
+#define PIN_PD26__FLEXCOM5_IO1 PINMUX_PIN(PIN_PD26, 2, 2)
+#define PIN_PD26__ADTRG PINMUX_PIN(PIN_PD26, 3, 3)
+#define PIN_PD26__TF1 PINMUX_PIN(PIN_PD26, 4, 2)
+#define PIN_PD26__ISC_D2 PINMUX_PIN(PIN_PD26, 5, 2)
+#define PIN_PD26__G1_RX1 PINMUX_PIN(PIN_PD26, 7, 1)
+#define PIN_PD27 123
+#define PIN_PD27__GPIO PINMUX_PIN(PIN_PD27, 0, 0)
+#define PIN_PD27__PDMC1_DS1 PINMUX_PIN(PIN_PD27, 1, 2)
+#define PIN_PD27__FLEXCOM5_IO2 PINMUX_PIN(PIN_PD27, 2, 2)
+#define PIN_PD27__TIOA0 PINMUX_PIN(PIN_PD27, 3, 3)
+#define PIN_PD27__TK1 PINMUX_PIN(PIN_PD27, 4, 2)
+#define PIN_PD27__ISC_D3 PINMUX_PIN(PIN_PD27, 5, 2)
+#define PIN_PD27__G1_RXER PINMUX_PIN(PIN_PD27, 7, 1)
+#define PIN_PD28 124
+#define PIN_PD28__GPIO PINMUX_PIN(PIN_PD28, 0, 0)
+#define PIN_PD28__RD0 PINMUX_PIN(PIN_PD28, 1, 2)
+#define PIN_PD28__FLEXCOM5_IO3 PINMUX_PIN(PIN_PD28, 2, 2)
+#define PIN_PD28__TIOB0 PINMUX_PIN(PIN_PD28, 3, 3)
+#define PIN_PD28__I2SMCC1_CK PINMUX_PIN(PIN_PD28, 4, 2)
+#define PIN_PD28__ISC_D4 PINMUX_PIN(PIN_PD28, 5, 2)
+#define PIN_PD28__PWML3 PINMUX_PIN(PIN_PD28, 6, 5)
+#define PIN_PD28__G1_MDC PINMUX_PIN(PIN_PD28, 7, 1)
+#define PIN_PD29 125
+#define PIN_PD29__GPIO PINMUX_PIN(PIN_PD29, 0, 0)
+#define PIN_PD29__RF0 PINMUX_PIN(PIN_PD29, 1, 2)
+#define PIN_PD29__FLEXCOM5_IO4 PINMUX_PIN(PIN_PD29, 2, 2)
+#define PIN_PD29__TCLK0 PINMUX_PIN(PIN_PD29, 3, 3)
+#define PIN_PD29__I2SMCC1_WS PINMUX_PIN(PIN_PD29, 4, 2)
+#define PIN_PD29__ISC_D5 PINMUX_PIN(PIN_PD29, 5, 2)
+#define PIN_PD29__PWMH3 PINMUX_PIN(PIN_PD29, 6, 5)
+#define PIN_PD29__G1_MDIO PINMUX_PIN(PIN_PD29, 7, 1)
+#define PIN_PD30 126
+#define PIN_PD30__GPIO PINMUX_PIN(PIN_PD30, 0, 0)
+#define PIN_PD30__RK0 PINMUX_PIN(PIN_PD30, 1, 2)
+#define PIN_PD30__FLEXCOM6_IO0 PINMUX_PIN(PIN_PD30, 2, 2)
+#define PIN_PD30__TIOA1 PINMUX_PIN(PIN_PD30, 3, 3)
+#define PIN_PD30__I2SMCC1_MCK PINMUX_PIN(PIN_PD30, 4, 2)
+#define PIN_PD30__ISC_D6 PINMUX_PIN(PIN_PD30, 5, 2)
+#define PIN_PD30__PWMEXTRG0 PINMUX_PIN(PIN_PD30, 6, 5)
+#define PIN_PD30__G1_TXCK PINMUX_PIN(PIN_PD30, 7, 1)
+#define PIN_PD31 127
+#define PIN_PD31__GPIO PINMUX_PIN(PIN_PD31, 0, 0)
+#define PIN_PD31__TD0 PINMUX_PIN(PIN_PD31, 1, 2)
+#define PIN_PD31__FLEXCOM6_IO1 PINMUX_PIN(PIN_PD31, 2, 2)
+#define PIN_PD31__TIOB1 PINMUX_PIN(PIN_PD31, 3, 3)
+#define PIN_PD31__I2SMCC1_DOUT0 PINMUX_PIN(PIN_PD31, 4, 2)
+#define PIN_PD31__ISC_D7 PINMUX_PIN(PIN_PD31, 5, 2)
+#define PIN_PD31__PWM_EXTRG1 PINMUX_PIN(PIN_PD31, 6, 5)
+#define PIN_PD31__G1_TX2 PINMUX_PIN(PIN_PD31, 7, 1)
+#define PIN_PE0 128
+#define PIN_PE0__GPIO PINMUX_PIN(PIN_PE0, 0, 0)
+#define PIN_PE0__TF0 PINMUX_PIN(PIN_PE0, 1, 2)
+#define PIN_PE0__FLEXCOM6_IO2 PINMUX_PIN(PIN_PE0, 2, 2)
+#define PIN_PE0__TCLK1 PINMUX_PIN(PIN_PE0, 3, 3)
+#define PIN_PE0__I2SMCC1_DOUT1 PINMUX_PIN(PIN_PE0, 4, 2)
+#define PIN_PE0__ISC_HSYNC PINMUX_PIN(PIN_PE0, 5, 2)
+#define PIN_PE0__PWMFI0 PINMUX_PIN(PIN_PE0, 6, 5)
+#define PIN_PE0__G1_TX3 PINMUX_PIN(PIN_PE0, 7, 1)
+#define PIN_PE1 129
+#define PIN_PE1__GPIO PINMUX_PIN(PIN_PE1, 0, 0)
+#define PIN_PE1__TK0 PINMUX_PIN(PIN_PE1, 1, 2)
+#define PIN_PE1__FLEXCOM6_IO3 PINMUX_PIN(PIN_PE1, 2, 2)
+#define PIN_PE1__TIOA2 PINMUX_PIN(PIN_PE1, 3, 3)
+#define PIN_PE1__I2SMCC1_DOUT2 PINMUX_PIN(PIN_PE1, 4, 2)
+#define PIN_PE1__ISC_VSYNC PINMUX_PIN(PIN_PE1, 5, 2)
+#define PIN_PE1__PWMFI1 PINMUX_PIN(PIN_PE1, 6, 5)
+#define PIN_PE1__G1_RX2 PINMUX_PIN(PIN_PE1, 7, 1)
+#define PIN_PE2 130
+#define PIN_PE2__GPIO PINMUX_PIN(PIN_PE2, 0, 0)
+#define PIN_PE2__PWML0 PINMUX_PIN(PIN_PE2, 1, 5)
+#define PIN_PE2__FLEXCOM6_IO4 PINMUX_PIN(PIN_PE2, 2, 2)
+#define PIN_PE2__TIOB2 PINMUX_PIN(PIN_PE2, 3, 3)
+#define PIN_PE2__I2SMCC1_DOUT3 PINMUX_PIN(PIN_PE2, 4, 2)
+#define PIN_PE2__ISC_FIELD PINMUX_PIN(PIN_PE2, 5, 2)
+#define PIN_PE2__G1_RX3 PINMUX_PIN(PIN_PE2, 7, 1)
+#define PIN_PE3 131
+#define PIN_PE3__GPIO PINMUX_PIN(PIN_PE3, 0, 0)
+#define PIN_PE3__PWMH0 PINMUX_PIN(PIN_PE3, 1, 5)
+#define PIN_PE3__FLEXCOM0_IO0 PINMUX_PIN(PIN_PE3, 2, 4)
+#define PIN_PE3__TCLK2 PINMUX_PIN(PIN_PE3, 3, 3)
+#define PIN_PE3__I2SMCC1_DIN0 PINMUX_PIN(PIN_PE3, 4, 2)
+#define PIN_PE3__ISC_PCK PINMUX_PIN(PIN_PE3, 5, 2)
+#define PIN_PE3__G1_RXCK PINMUX_PIN(PIN_PE3, 7, 1)
+#define PIN_PE4 132
+#define PIN_PE4__GPIO PINMUX_PIN(PIN_PE4, 0, 0)
+#define PIN_PE4__PWML1 PINMUX_PIN(PIN_PE4, 1, 5)
+#define PIN_PE4__FLEXCOM0_IO1 PINMUX_PIN(PIN_PE4, 2, 4)
+#define PIN_PE4__TIOA3 PINMUX_PIN(PIN_PE4, 3, 3)
+#define PIN_PE4__I2SMCC1_DIN1 PINMUX_PIN(PIN_PE4, 4, 2)
+#define PIN_PE4__ISC_D8 PINMUX_PIN(PIN_PE4, 5, 2)
+#define PIN_PE4__G1_TXER PINMUX_PIN(PIN_PE4, 7, 1)
+#define PIN_PE5 133
+#define PIN_PE5__GPIO PINMUX_PIN(PIN_PE5, 0, 0)
+#define PIN_PE5__PWMH1 PINMUX_PIN(PIN_PE5, 1, 5)
+#define PIN_PE5__FLEXCOM0_IO2 PINMUX_PIN(PIN_PE5, 2, 4)
+#define PIN_PE5__TIOB3 PINMUX_PIN(PIN_PE5, 3, 3)
+#define PIN_PE5__I2SMCC1_DIN2 PINMUX_PIN(PIN_PE5, 4, 2)
+#define PIN_PE5__ISC_D9 PINMUX_PIN(PIN_PE5, 5, 2)
+#define PIN_PE5__G1_COL PINMUX_PIN(PIN_PE5, 7, 1)
+#define PIN_PE6 134
+#define PIN_PE6__GPIO PINMUX_PIN(PIN_PE6, 0, 0)
+#define PIN_PE6__PWML2 PINMUX_PIN(PIN_PE6, 1, 5)
+#define PIN_PE6__FLEXCOM0_IO3 PINMUX_PIN(PIN_PE6, 2, 4)
+#define PIN_PE6__TCLK3 PINMUX_PIN(PIN_PE6, 3, 3)
+#define PIN_PE6__I2SMCC1_DIN3 PINMUX_PIN(PIN_PE6, 4, 2)
+#define PIN_PE6__ISC_D10 PINMUX_PIN(PIN_PE6, 5, 2)
+#define PIN_PE6__G1_CRS PINMUX_PIN(PIN_PE6, 7, 1)
+#define PIN_PE7 135
+#define PIN_PE7__GPIO PINMUX_PIN(PIN_PE7, 0, 0)
+#define PIN_PE7__PWMH2 PINMUX_PIN(PIN_PE7, 1, 5)
+#define PIN_PE7__FLEXCOM0_IO4 PINMUX_PIN(PIN_PE7, 2, 4)
+#define PIN_PE7__TIOA4 PINMUX_PIN(PIN_PE7, 3, 3)
+#define PIN_PE7__ISC_D11 PINMUX_PIN(PIN_PE7, 5, 2)
+#define PIN_PE7__G1_TSUCOMP PINMUX_PIN(PIN_PE7, 7, 1)
+
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 85524004f9e..be1415f909a 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -47,6 +47,10 @@ config SAM9X60
bool
select CPU_ARM926EJS
+config SAMA7G5
+ bool
+ select CPU_V7A
+
config SAMA5D2
bool
select CPU_V7A
diff --git a/arch/arm/mach-at91/armv7/Makefile b/arch/arm/mach-at91/armv7/Makefile
index 9ced3dc0c12..55477560a86 100644
--- a/arch/arm/mach-at91/armv7/Makefile
+++ b/arch/arm/mach-at91/armv7/Makefile
@@ -9,6 +9,7 @@
obj-$(CONFIG_SAMA5D2) += sama5d2_devices.o
obj-$(CONFIG_SAMA5D3) += sama5d3_devices.o
obj-$(CONFIG_SAMA5D4) += sama5d4_devices.o
+obj-$(CONFIG_SAMA7G5) += sama7g5_devices.o
obj-y += clock.o
obj-y += cpu.o
obj-y += reset.o
diff --git a/arch/arm/mach-at91/armv7/cpu.c b/arch/arm/mach-at91/armv7/cpu.c
index a8f4356ce94..8b7355042ba 100644
--- a/arch/arm/mach-at91/armv7/cpu.c
+++ b/arch/arm/mach-at91/armv7/cpu.c
@@ -29,6 +29,7 @@ int arch_cpu_init(void)
void arch_preboot_os(void)
{
+#if (IS_ENABLED(CONFIG_ATMEL_PIT_TIMER))
ulong cpiv;
at91_pit_t *pit = (at91_pit_t *)ATMEL_BASE_PIT;
@@ -40,6 +41,7 @@ void arch_preboot_os(void)
* without waiting for wrapping back to 0
*/
writel(cpiv + 0x1000, &pit->mr);
+#endif
}
#if defined(CONFIG_DISPLAY_CPUINFO)
diff --git a/arch/arm/mach-at91/armv7/sama7g5_devices.c b/arch/arm/mach-at91/armv7/sama7g5_devices.c
new file mode 100644
index 00000000000..a58f671f72d
--- /dev/null
+++ b/arch/arm/mach-at91/armv7/sama7g5_devices.c
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Microchip Technology, Inc.
+ * Eugen Hristev <eugen.hristev@microchip.com>
+ */
+
+char *get_cpu_name(void)
+{
+ return "SAMA7G5";
+}
+
diff --git a/arch/arm/mach-at91/include/mach/at91_common.h b/arch/arm/mach-at91/include/mach/at91_common.h
index 01e00c508a8..f7b411cf7df 100644
--- a/arch/arm/mach-at91/include/mach/at91_common.h
+++ b/arch/arm/mach-at91/include/mach/at91_common.h
@@ -40,6 +40,7 @@ void configure_ddrcfg_input_buffers(bool open);
#endif
int at91_set_ethaddr(int offset);
+int at91_set_eth1addr(int offset);
void at91_spi_nor_set_ethaddr(void);
int at91_video_show_board_info(void);
diff --git a/arch/arm/mach-at91/include/mach/hardware.h b/arch/arm/mach-at91/include/mach/hardware.h
index 88acca85499..0a16c8ff088 100644
--- a/arch/arm/mach-at91/include/mach/hardware.h
+++ b/arch/arm/mach-at91/include/mach/hardware.h
@@ -24,6 +24,8 @@
# include <asm/arch/at91sam9x5.h>
#elif defined(CONFIG_SAM9X60)
# include <asm/arch/sam9x60.h>
+#elif defined(CONFIG_SAMA7G5)
+# include <asm/arch/sama7g5.h>
#elif defined(CONFIG_SAMA5D2)
# include <asm/arch/sama5d2.h>
#elif defined(CONFIG_SAMA5D3)
diff --git a/arch/arm/mach-at91/include/mach/sama7g5.h b/arch/arm/mach-at91/include/mach/sama7g5.h
new file mode 100644
index 00000000000..ae43e8700be
--- /dev/null
+++ b/arch/arm/mach-at91/include/mach/sama7g5.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Chip-specific header file for the SAMA7G5 SoC
+ *
+ * Copyright (C) 2020 Microchip Technology, Inc. and its subsidiaries
+ * Eugen Hristev <eugen.hristev@microchip.com>
+ */
+
+#ifndef __SAMA7G5_H__
+#define __SAMA7G5_H__
+
+/*
+ * Peripheral identifiers/interrupts.
+ */
+#define ATMEL_ID_FLEXCOM0 38
+#define ATMEL_ID_FLEXCOM1 39
+#define ATMEL_ID_FLEXCOM2 40
+#define ATMEL_ID_FLEXCOM3 41
+
+#define ATMEL_ID_SDMMC0 80
+#define ATMEL_ID_SDMMC1 81
+
+#define ATMEL_ID_PIT64B0 70
+#define ATMEL_ID_PIT64B ATMEL_ID_PIT64B0
+
+#define ATMEL_CHIPID_CIDR 0xe0020000
+#define ATMEL_CHIPID_EXID 0xe0020004
+/*
+ * User Peripherals physical base addresses.
+ */
+#define ATMEL_BASE_PIOA 0xe0014000
+#define ATMEL_BASE_PIOB (ATMEL_BASE_PIOA + 0x40)
+#define ATMEL_BASE_PIOC (ATMEL_BASE_PIOB + 0x40)
+#define ATMEL_BASE_PIOD (ATMEL_BASE_PIOC + 0x40)
+#define ATMEL_BASE_PIOE (ATMEL_BASE_PIOD + 0x40)
+
+#define ATMEL_PIO_PORTS 5
+
+#define CPU_HAS_PCR
+
+#define ATMEL_BASE_PMC 0xe0018000
+
+#define ATMEL_BASE_WDT 0xe001c000
+#define ATMEL_BASE_RSTC 0xe001d000
+#define ATMEL_BASE_WDTS 0xe001d180
+#define ATMEL_BASE_SCKCR 0xe001d050
+
+#define ATMEL_BASE_SDMMC0 0xe1204000
+#define ATMEL_BASE_SDMMC1 0xe1208000
+
+#define ATMEL_BASE_PIT64B0 0xe1800000
+
+#define ATMEL_BASE_FLEXCOM0 0xe1818000
+#define ATMEL_BASE_FLEXCOM1 0xe181c000
+#define ATMEL_BASE_FLEXCOM2 0xe1820000
+#define ATMEL_BASE_FLEXCOM3 0xe1824000
+#define ATMEL_BASE_FLEXCOM4 0xe2018000
+
+#define ATMEL_BASE_TZC400 0xe3000000
+
+#define ATMEL_BASE_UMCTL2 0xe3800000
+#define ATMEL_BASE_UMCTL2_MP 0xe38003f8
+#define ATMEL_BASE_PUBL 0xe3804000
+
+#define ATMEL_NUM_FLEXCOM 12
+#define ATMEL_PIO_PORTS 5
+
+#define ATMEL_BASE_PIT64BC ATMEL_BASE_PIT64B0
+
+#ifndef __ASSEMBLY__
+char *get_cpu_name(void);
+#endif
+
+#endif /* #ifndef __SAMA7G5_H__ */
diff --git a/board/atmel/common/mac_eeprom.c b/board/atmel/common/mac_eeprom.c
index 2205dd30f8f..a723ba723c9 100644
--- a/board/atmel/common/mac_eeprom.c
+++ b/board/atmel/common/mac_eeprom.c
@@ -36,3 +36,36 @@ int at91_set_ethaddr(int offset)
return 0;
}
+
+/* this function will set eth1addr from a second eeprom, if available */
+int at91_set_eth1addr(int offset)
+{
+ const int ETH_ADDR_LEN = 6;
+ unsigned char ethaddr[ETH_ADDR_LEN];
+ /* configure eth1addr for second interface */
+ const char *ETHADDR_NAME = "eth1addr";
+ struct udevice *dev;
+ int ret;
+
+ if (env_get(ETHADDR_NAME))
+ return 0;
+
+ /* first eeprom is retrieved, this is for the first interface */
+ ret = uclass_first_device_err(UCLASS_I2C_EEPROM, &dev);
+ if (ret)
+ return ret;
+
+ /* attempt to obtain a second eeprom device */
+ ret = uclass_next_device(&dev);
+ if (ret)
+ return ret;
+
+ ret = i2c_eeprom_read(dev, offset, ethaddr, 6);
+ if (ret)
+ return ret;
+
+ if (is_valid_ethaddr(ethaddr))
+ eth_env_set_enetaddr(ETHADDR_NAME, ethaddr);
+
+ return 0;
+}
diff --git a/drivers/clk/at91/Kconfig b/drivers/clk/at91/Kconfig
index 8d482a27523..4abc8026b4d 100644
--- a/drivers/clk/at91/Kconfig
+++ b/drivers/clk/at91/Kconfig
@@ -54,3 +54,10 @@ config AT91_GENERIC_CLK
that may be different from the system clock. This second
clock is the generic clock (GCLK) and is managed by
the PMC via PMC_PCR register.
+
+config AT91_SAM9X60_PLL
+ bool "PLL support for SAM9X60 SoCs"
+ depends on CLK_AT91
+ help
+ This option is used to enable the AT91 SAM9X60's PLL clock
+ driver.
diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
index 8c197ff949a..2453c38af1a 100644
--- a/drivers/clk/at91/Makefile
+++ b/drivers/clk/at91/Makefile
@@ -2,11 +2,14 @@
# Makefile for at91 specific clk
#
-obj-y += pmc.o sckc.o
-obj-y += clk-slow.o clk-main.o clk-plla.o clk-plladiv.o clk-master.o
-obj-y += clk-system.o clk-peripheral.o
+ifdef CONFIG_CLK_CCF
+obj-y += pmc.o sckc.o clk-main.o clk-master.o clk-programmable.o clk-system.o
+obj-y += clk-peripheral.o
+obj-$(CONFIG_AT91_GENERIC_CLK) += clk-generic.o
obj-$(CONFIG_AT91_UTMI) += clk-utmi.o
-obj-$(CONFIG_AT91_USB_CLK) += clk-usb.o
-obj-$(CONFIG_AT91_H32MX) += clk-h32mx.o
-obj-$(CONFIG_AT91_GENERIC_CLK) += clk-generated.o
+obj-$(CONFIG_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o
+obj-$(CONFIG_SAMA7G5) += sama7g5.o
+else
+obj-y += compat.o
+endif
diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c
deleted file mode 100644
index c0610940c3b..00000000000
--- a/drivers/clk/at91/clk-generated.c
+++ /dev/null
@@ -1,178 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2016 Atmel Corporation
- * Wenyou.Yang <wenyou.yang@atmel.com>
- */
-
-#include <common.h>
-#include <clk-uclass.h>
-#include <dm.h>
-#include <log.h>
-#include <malloc.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <mach/at91_pmc.h>
-#include "pmc.h"
-
-DECLARE_GLOBAL_DATA_PTR;
-
-#define GENERATED_SOURCE_MAX 6
-#define GENERATED_MAX_DIV 255
-
-/**
- * generated_clk_bind() - for the generated clock driver
- * Recursively bind its children as clk devices.
- *
- * @return: 0 on success, or negative error code on failure
- */
-static int generated_clk_bind(struct udevice *dev)
-{
- return at91_clk_sub_device_bind(dev, "generic-clk");
-}
-
-static const struct udevice_id generated_clk_match[] = {
- { .compatible = "atmel,sama5d2-clk-generated" },
- {}
-};
-
-U_BOOT_DRIVER(generated_clk) = {
- .name = "generated-clk",
- .id = UCLASS_MISC,
- .of_match = generated_clk_match,
- .bind = generated_clk_bind,
-};
-
-/*-------------------------------------------------------------*/
-
-struct generic_clk_priv {
- u32 num_parents;
-};
-
-static ulong generic_clk_get_rate(struct clk *clk)
-{
- struct pmc_platdata *plat = dev_get_platdata(clk->dev);
- struct at91_pmc *pmc = plat->reg_base;
- struct clk parent;
- ulong clk_rate;
- u32 tmp, gckdiv;
- u8 clock_source, parent_index;
- int ret;
-
- writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr);
- tmp = readl(&pmc->pcr);
- clock_source = (tmp >> AT91_PMC_PCR_GCKCSS_OFFSET) &
- AT91_PMC_PCR_GCKCSS_MASK;
- gckdiv = (tmp >> AT91_PMC_PCR_GCKDIV_OFFSET) & AT91_PMC_PCR_GCKDIV_MASK;
-
- parent_index = clock_source - 1;
- ret = clk_get_by_index(dev_get_parent(clk->dev), parent_index, &parent);
- if (ret)
- return 0;
-
- clk_rate = clk_get_rate(&parent) / (gckdiv + 1);
-
- clk_free(&parent);
-
- return clk_rate;
-}
-
-static ulong generic_clk_set_rate(struct clk *clk, ulong rate)
-{
- struct pmc_platdata *plat = dev_get_platdata(clk->dev);
- struct at91_pmc *pmc = plat->reg_base;
- struct generic_clk_priv *priv = dev_get_priv(clk->dev);
- struct clk parent, best_parent;
- ulong tmp_rate, best_rate = rate, parent_rate;
- int tmp_diff, best_diff = -1;
- u32 div, best_div = 0;
- u8 best_parent_index, best_clock_source = 0;
- u8 i;
- u32 tmp;
- int ret;
-
- for (i = 0; i < priv->num_parents; i++) {
- ret = clk_get_by_index(dev_get_parent(clk->dev), i, &parent);
- if (ret)
- return ret;
-
- parent_rate = clk_get_rate(&parent);
- if (IS_ERR_VALUE(parent_rate))
- return parent_rate;
-
- for (div = 1; div < GENERATED_MAX_DIV + 2; div++) {
- tmp_rate = DIV_ROUND_CLOSEST(parent_rate, div);
- tmp_diff = abs(rate - tmp_rate);
-
- if (best_diff < 0 || best_diff > tmp_diff) {
- best_rate = tmp_rate;
- best_diff = tmp_diff;
-
- best_div = div - 1;
- best_parent = parent;
- best_parent_index = i;
- best_clock_source = best_parent_index + 1;
- }
-
- if (!best_diff || tmp_rate < rate)
- break;
- }
-
- if (!best_diff)
- break;
- }
-
- debug("GCK: best parent: %s, best_rate = %ld, best_div = %d\n",
- best_parent.dev->name, best_rate, best_div);
-
- ret = clk_enable(&best_parent);
- if (ret)
- return ret;
-
- writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr);
- tmp = readl(&pmc->pcr);
- tmp &= ~(AT91_PMC_PCR_GCKDIV | AT91_PMC_PCR_GCKCSS);
- tmp |= AT91_PMC_PCR_GCKCSS_(best_clock_source) |
- AT91_PMC_PCR_CMD_WRITE |
- AT91_PMC_PCR_GCKDIV_(best_div) |
- AT91_PMC_PCR_GCKEN;
- writel(tmp, &pmc->pcr);
-
- while (!(readl(&pmc->sr) & AT91_PMC_GCKRDY))
- ;
-
- return 0;
-}
-
-static struct clk_ops generic_clk_ops = {
- .of_xlate = at91_clk_of_xlate,
- .get_rate = generic_clk_get_rate,
- .set_rate = generic_clk_set_rate,
-};
-
-static int generic_clk_ofdata_to_platdata(struct udevice *dev)
-{
- struct generic_clk_priv *priv = dev_get_priv(dev);
- u32 cells[GENERATED_SOURCE_MAX];
- u32 num_parents;
-
- num_parents = fdtdec_get_int_array_count(gd->fdt_blob,
- dev_of_offset(dev_get_parent(dev)), "clocks", cells,
- GENERATED_SOURCE_MAX);
-
- if (!num_parents)
- return -1;
-
- priv->num_parents = num_parents;
-
- return 0;
-}
-
-U_BOOT_DRIVER(generic_clk) = {
- .name = "generic-clk",
- .id = UCLASS_CLK,
- .probe = at91_clk_probe,
- .ofdata_to_platdata = generic_clk_ofdata_to_platdata,
- .priv_auto_alloc_size = sizeof(struct generic_clk_priv),
- .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
- .ops = &generic_clk_ops,
-};
diff --git a/drivers/clk/at91/clk-generic.c b/drivers/clk/at91/clk-generic.c
new file mode 100644
index 00000000000..87738b7b5bf
--- /dev/null
+++ b/drivers/clk/at91/clk-generic.c
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Generic clock support for AT91 architectures.
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ *
+ * Based on drivers/clk/at91/clk-generated.c from Linux.
+ */
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <linux/io.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/at91_pmc.h>
+
+#include "pmc.h"
+
+#define UBOOT_DM_CLK_AT91_GCK "at91-gck-clk"
+
+#define GENERATED_MAX_DIV 255
+
+struct clk_gck {
+ void __iomem *base;
+ const u32 *clk_mux_table;
+ const u32 *mux_table;
+ const struct clk_pcr_layout *layout;
+ struct clk_range range;
+ struct clk clk;
+ u32 num_parents;
+ u32 id;
+};
+
+#define to_clk_gck(_c) container_of(_c, struct clk_gck, clk)
+
+static int clk_gck_enable(struct clk *clk)
+{
+ struct clk_gck *gck = to_clk_gck(clk);
+
+ pmc_write(gck->base, gck->layout->offset,
+ (gck->id & gck->layout->pid_mask));
+ pmc_update_bits(gck->base, gck->layout->offset,
+ gck->layout->cmd | AT91_PMC_PCR_GCKEN,
+ gck->layout->cmd | AT91_PMC_PCR_GCKEN);
+
+ return 0;
+}
+
+static int clk_gck_disable(struct clk *clk)
+{
+ struct clk_gck *gck = to_clk_gck(clk);
+
+ pmc_write(gck->base, gck->layout->offset,
+ (gck->id & gck->layout->pid_mask));
+ pmc_update_bits(gck->base, gck->layout->offset,
+ gck->layout->cmd | AT91_PMC_PCR_GCKEN,
+ gck->layout->cmd);
+
+ return 0;
+}
+
+static int clk_gck_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct clk_gck *gck = to_clk_gck(clk);
+ int index;
+
+ index = at91_clk_mux_val_to_index(gck->clk_mux_table, gck->num_parents,
+ parent->id);
+ if (index < 0)
+ return index;
+
+ index = at91_clk_mux_index_to_val(gck->mux_table, gck->num_parents,
+ index);
+ if (index < 0)
+ return index;
+
+ pmc_write(gck->base, gck->layout->offset,
+ (gck->id & gck->layout->pid_mask));
+ pmc_update_bits(gck->base, gck->layout->offset,
+ gck->layout->gckcss_mask | gck->layout->cmd,
+ (index << (ffs(gck->layout->gckcss_mask) - 1)) |
+ gck->layout->cmd);
+
+ return 0;
+}
+
+static ulong clk_gck_set_rate(struct clk *clk, ulong rate)
+{
+ struct clk_gck *gck = to_clk_gck(clk);
+ ulong parent_rate = clk_get_parent_rate(clk);
+ u32 div;
+
+ if (!rate || !parent_rate)
+ return 0;
+
+ if (gck->range.max && rate > gck->range.max)
+ return 0;
+
+ div = DIV_ROUND_CLOSEST(parent_rate, rate);
+ if (div > GENERATED_MAX_DIV + 1 || !div)
+ return 0;
+
+ pmc_write(gck->base, gck->layout->offset,
+ (gck->id & gck->layout->pid_mask));
+ pmc_update_bits(gck->base, gck->layout->offset,
+ AT91_PMC_PCR_GCKDIV_MASK | gck->layout->cmd,
+ ((div - 1) << (ffs(AT91_PMC_PCR_GCKDIV_MASK) - 1)) |
+ gck->layout->cmd);
+
+ return parent_rate / div;
+}
+
+static ulong clk_gck_get_rate(struct clk *clk)
+{
+ struct clk_gck *gck = to_clk_gck(clk);
+ ulong parent_rate = clk_get_parent_rate(clk);
+ u32 val, div;
+
+ if (!parent_rate)
+ return 0;
+
+ pmc_write(gck->base, gck->layout->offset,
+ (gck->id & gck->layout->pid_mask));
+ pmc_read(gck->base, gck->layout->offset, &val);
+
+ div = (val & AT91_PMC_PCR_GCKDIV_MASK) >>
+ (ffs(AT91_PMC_PCR_GCKDIV_MASK) - 1);
+
+ return parent_rate / (div + 1);
+}
+
+static const struct clk_ops gck_ops = {
+ .enable = clk_gck_enable,
+ .disable = clk_gck_disable,
+ .set_parent = clk_gck_set_parent,
+ .set_rate = clk_gck_set_rate,
+ .get_rate = clk_gck_get_rate,
+};
+
+struct clk *
+at91_clk_register_generic(void __iomem *base,
+ const struct clk_pcr_layout *layout,
+ const char *name, const char * const *parent_names,
+ const u32 *clk_mux_table, const u32 *mux_table,
+ u8 num_parents, u8 id,
+ const struct clk_range *range)
+{
+ struct clk_gck *gck;
+ struct clk *clk;
+ int ret, index;
+ u32 val;
+
+ if (!base || !layout || !name || !parent_names || !num_parents ||
+ !clk_mux_table || !mux_table || !range)
+ return ERR_PTR(-EINVAL);
+
+ gck = kzalloc(sizeof(*gck), GFP_KERNEL);
+ if (!gck)
+ return ERR_PTR(-ENOMEM);
+
+ gck->id = id;
+ gck->base = base;
+ gck->range = *range;
+ gck->layout = layout;
+ gck->clk_mux_table = clk_mux_table;
+ gck->mux_table = mux_table;
+ gck->num_parents = num_parents;
+
+ clk = &gck->clk;
+ clk->flags = CLK_GET_RATE_NOCACHE;
+
+ pmc_write(gck->base, gck->layout->offset,
+ (gck->id & gck->layout->pid_mask));
+ pmc_read(gck->base, gck->layout->offset, &val);
+
+ val = (val & gck->layout->gckcss_mask) >>
+ (ffs(gck->layout->gckcss_mask) - 1);
+
+ index = at91_clk_mux_val_to_index(gck->mux_table, gck->num_parents,
+ val);
+ if (index < 0) {
+ kfree(gck);
+ return ERR_PTR(index);
+ }
+
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_GCK, name,
+ parent_names[index]);
+ if (ret) {
+ kfree(gck);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(at91_gck_clk) = {
+ .name = UBOOT_DM_CLK_AT91_GCK,
+ .id = UCLASS_CLK,
+ .ops = &gck_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/at91/clk-h32mx.c b/drivers/clk/at91/clk-h32mx.c
deleted file mode 100644
index 86bb71f6128..00000000000
--- a/drivers/clk/at91/clk-h32mx.c
+++ /dev/null
@@ -1,56 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2016 Atmel Corporation
- * Wenyou.Yang <wenyou.yang@atmel.com>
- */
-
-#include <common.h>
-#include <clk-uclass.h>
-#include <dm.h>
-#include <dm/device_compat.h>
-#include <dm/util.h>
-#include <linux/io.h>
-#include <mach/at91_pmc.h>
-#include "pmc.h"
-
-DECLARE_GLOBAL_DATA_PTR;
-
-#define H32MX_MAX_FREQ 90000000
-
-static ulong sama5d4_h32mx_clk_get_rate(struct clk *clk)
-{
- struct pmc_platdata *plat = dev_get_platdata(clk->dev);
- struct at91_pmc *pmc = plat->reg_base;
- ulong rate = gd->arch.mck_rate_hz;
-
- if (readl(&pmc->mckr) & AT91_PMC_MCKR_H32MXDIV)
- rate /= 2;
-
- if (rate > H32MX_MAX_FREQ)
- dev_dbg(clk->dev, "H32MX clock is too fast\n");
-
- return rate;
-}
-
-static struct clk_ops sama5d4_h32mx_clk_ops = {
- .get_rate = sama5d4_h32mx_clk_get_rate,
-};
-
-static int sama5d4_h32mx_clk_probe(struct udevice *dev)
-{
- return at91_pmc_core_probe(dev);
-}
-
-static const struct udevice_id sama5d4_h32mx_clk_match[] = {
- { .compatible = "atmel,sama5d4-clk-h32mx" },
- {}
-};
-
-U_BOOT_DRIVER(sama5d4_h32mx_clk) = {
- .name = "sama5d4-h32mx-clk",
- .id = UCLASS_CLK,
- .of_match = sama5d4_h32mx_clk_match,
- .probe = sama5d4_h32mx_clk_probe,
- .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
- .ops = &sama5d4_h32mx_clk_ops,
-};
diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c
index b31a1cb6828..b52d926f339 100644
--- a/drivers/clk/at91/clk-main.c
+++ b/drivers/clk/at91/clk-main.c
@@ -1,54 +1,387 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2016 Atmel Corporation
- * Wenyou.Yang <wenyou.yang@atmel.com>
+ * Main clock support for AT91 architectures.
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ *
+ * Based on drivers/clk/at91/clk-main.c from Linux.
*/
+#include <asm/processor.h>
#include <common.h>
#include <clk-uclass.h>
#include <dm.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/at91_pmc.h>
+#include <linux/delay.h>
#include <linux/io.h>
-#include <mach/at91_pmc.h>
#include "pmc.h"
-DECLARE_GLOBAL_DATA_PTR;
+#define UBOOT_DM_CLK_AT91_MAIN_RC "at91-main-rc-clk"
+#define UBOOT_DM_CLK_AT91_MAIN_OSC "at91-main-osc-clk"
+#define UBOOT_DM_CLK_AT91_RM9200_MAIN "at91-rm9200-main-clk"
+#define UBOOT_DM_CLK_AT91_SAM9X5_MAIN "at91-sam9x5-main-clk"
-static int main_osc_clk_enable(struct clk *clk)
+#define MOR_KEY_MASK GENMASK(23, 16)
+#define USEC_PER_SEC 1000000UL
+#define SLOW_CLOCK_FREQ 32768
+
+#define clk_main_parent_select(s) (((s) & \
+ (AT91_PMC_MOSCEN | \
+ AT91_PMC_OSCBYPASS)) ? 1 : 0)
+
+struct clk_main_rc {
+ void __iomem *reg;
+ struct clk clk;
+};
+
+#define to_clk_main_rc(_clk) container_of(_clk, struct clk_main_rc, clk)
+
+struct clk_main_osc {
+ void __iomem *reg;
+ struct clk clk;
+};
+
+#define to_clk_main_osc(_clk) container_of(_clk, struct clk_main_osc, clk)
+
+struct clk_main {
+ void __iomem *reg;
+ const unsigned int *clk_mux_table;
+ const char * const *parent_names;
+ unsigned int num_parents;
+ int type;
+ struct clk clk;
+};
+
+#define to_clk_main(_clk) container_of(_clk, struct clk_main, clk)
+
+static int main_rc_enable(struct clk *clk)
+{
+ struct clk_main_rc *main_rc = to_clk_main_rc(clk);
+ void __iomem *reg = main_rc->reg;
+ unsigned int val;
+
+ pmc_read(reg, AT91_CKGR_MOR, &val);
+
+ if (!(val & AT91_PMC_MOSCRCEN)) {
+ pmc_update_bits(reg, AT91_CKGR_MOR,
+ MOR_KEY_MASK | AT91_PMC_MOSCRCEN,
+ AT91_PMC_KEY | AT91_PMC_MOSCRCEN);
+ }
+
+ pmc_read(reg, AT91_PMC_SR, &val);
+ while (!(val & AT91_PMC_MOSCRCS)) {
+ pmc_read(reg, AT91_PMC_SR, &val);
+ debug("waiting for main rc...\n");
+ cpu_relax();
+ }
+
+ return 0;
+}
+
+static int main_rc_disable(struct clk *clk)
{
- struct pmc_platdata *plat = dev_get_platdata(clk->dev);
- struct at91_pmc *pmc = plat->reg_base;
+ struct clk_main_rc *main_rc = to_clk_main_rc(clk);
+ struct reg *reg = main_rc->reg;
+ unsigned int val;
+
+ pmc_read(reg, AT91_CKGR_MOR, &val);
- if (readl(&pmc->sr) & AT91_PMC_MOSCSELS)
+ if (!(val & AT91_PMC_MOSCRCEN))
return 0;
- return -EINVAL;
+ pmc_update_bits(reg, AT91_CKGR_MOR, MOR_KEY_MASK | AT91_PMC_MOSCRCEN,
+ AT91_PMC_KEY);
+
+ return 0;
}
-static ulong main_osc_clk_get_rate(struct clk *clk)
+static const struct clk_ops main_rc_clk_ops = {
+ .enable = main_rc_enable,
+ .disable = main_rc_disable,
+ .get_rate = clk_generic_get_rate,
+};
+
+struct clk *at91_clk_main_rc(void __iomem *reg, const char *name,
+ const char *parent_name)
{
- return gd->arch.main_clk_rate_hz;
+ struct clk_main_rc *main_rc;
+ struct clk *clk;
+ int ret;
+
+ if (!reg || !name || !parent_name)
+ return ERR_PTR(-EINVAL);
+
+ main_rc = kzalloc(sizeof(*main_rc), GFP_KERNEL);
+ if (!main_rc)
+ return ERR_PTR(-ENOMEM);
+
+ main_rc->reg = reg;
+ clk = &main_rc->clk;
+
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_MAIN_RC, name,
+ parent_name);
+ if (ret) {
+ kfree(main_rc);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
}
-static struct clk_ops main_osc_clk_ops = {
- .enable = main_osc_clk_enable,
- .get_rate = main_osc_clk_get_rate,
+U_BOOT_DRIVER(at91_main_rc_clk) = {
+ .name = UBOOT_DM_CLK_AT91_MAIN_RC,
+ .id = UCLASS_CLK,
+ .ops = &main_rc_clk_ops,
+ .flags = DM_FLAG_PRE_RELOC,
};
-static int main_osc_clk_probe(struct udevice *dev)
+static int clk_main_osc_enable(struct clk *clk)
{
- return at91_pmc_core_probe(dev);
+ struct clk_main_osc *main = to_clk_main_osc(clk);
+ void __iomem *reg = main->reg;
+ unsigned int val;
+
+ pmc_read(reg, AT91_CKGR_MOR, &val);
+ val &= ~MOR_KEY_MASK;
+
+ if (val & AT91_PMC_OSCBYPASS)
+ return 0;
+
+ if (!(val & AT91_PMC_MOSCEN)) {
+ val |= AT91_PMC_MOSCEN | AT91_PMC_KEY;
+ pmc_write(reg, AT91_CKGR_MOR, val);
+ }
+
+ pmc_read(reg, AT91_PMC_SR, &val);
+ while (!(val & AT91_PMC_MOSCS)) {
+ pmc_read(reg, AT91_PMC_SR, &val);
+ debug("waiting for main osc..\n");
+ cpu_relax();
+ }
+
+ return 0;
+}
+
+static int clk_main_osc_disable(struct clk *clk)
+{
+ struct clk_main_osc *main = to_clk_main_osc(clk);
+ void __iomem *reg = main->reg;
+ unsigned int val;
+
+ pmc_read(reg, AT91_CKGR_MOR, &val);
+ if (val & AT91_PMC_OSCBYPASS)
+ return 0;
+
+ if (!(val & AT91_PMC_MOSCEN))
+ return 0;
+
+ val &= ~(AT91_PMC_KEY | AT91_PMC_MOSCEN);
+ pmc_write(reg, AT91_CKGR_MOR, val | AT91_PMC_KEY);
+
+ return 0;
}
-static const struct udevice_id main_osc_clk_match[] = {
- { .compatible = "atmel,at91sam9x5-clk-main" },
- {}
+static const struct clk_ops main_osc_clk_ops = {
+ .enable = clk_main_osc_enable,
+ .disable = clk_main_osc_disable,
+ .get_rate = clk_generic_get_rate,
};
-U_BOOT_DRIVER(at91sam9x5_main_osc_clk) = {
- .name = "at91sam9x5-main-osc-clk",
+struct clk *at91_clk_main_osc(void __iomem *reg, const char *name,
+ const char *parent_name, bool bypass)
+{
+ struct clk_main_osc *main;
+ struct clk *clk;
+ int ret;
+
+ if (!reg || !name || !parent_name)
+ return ERR_PTR(-EINVAL);
+
+ main = kzalloc(sizeof(*main), GFP_KERNEL);
+ if (!main)
+ return ERR_PTR(-ENOMEM);
+
+ main->reg = reg;
+ clk = &main->clk;
+
+ if (bypass) {
+ pmc_update_bits(reg, AT91_CKGR_MOR,
+ MOR_KEY_MASK | AT91_PMC_OSCBYPASS,
+ AT91_PMC_KEY | AT91_PMC_OSCBYPASS);
+ }
+
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_MAIN_OSC, name, parent_name);
+ if (ret) {
+ kfree(main);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(at91_main_osc_clk) = {
+ .name = UBOOT_DM_CLK_AT91_MAIN_OSC,
.id = UCLASS_CLK,
- .of_match = main_osc_clk_match,
- .probe = main_osc_clk_probe,
- .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
.ops = &main_osc_clk_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+static int clk_main_probe_frequency(void __iomem *reg)
+{
+ unsigned int cycles = 16;
+ unsigned int cycle = DIV_ROUND_UP(USEC_PER_SEC, SLOW_CLOCK_FREQ);
+ unsigned int mcfr;
+
+ while (cycles--) {
+ pmc_read(reg, AT91_CKGR_MCFR, &mcfr);
+ if (mcfr & AT91_PMC_MAINRDY)
+ return 0;
+ udelay(cycle);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int clk_rm9200_main_enable(struct clk *clk)
+{
+ struct clk_main *main = to_clk_main(clk);
+
+ return clk_main_probe_frequency(main->reg);
+}
+
+static const struct clk_ops rm9200_main_clk_ops = {
+ .enable = clk_rm9200_main_enable,
+};
+
+struct clk *at91_clk_rm9200_main(void __iomem *reg, const char *name,
+ const char *parent_name)
+{
+ struct clk_main *main;
+ struct clk *clk;
+ int ret;
+
+ if (!reg || !name || !parent_name)
+ return ERR_PTR(-EINVAL);
+
+ main = kzalloc(sizeof(*main), GFP_KERNEL);
+ if (!main)
+ return ERR_PTR(-ENOMEM);
+
+ main->reg = reg;
+ clk = &main->clk;
+
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_RM9200_MAIN, name,
+ parent_name);
+ if (ret) {
+ kfree(main);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(at91_rm9200_main_clk) = {
+ .name = UBOOT_DM_CLK_AT91_RM9200_MAIN,
+ .id = UCLASS_CLK,
+ .ops = &rm9200_main_clk_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+static inline bool clk_sam9x5_main_ready(void __iomem *reg)
+{
+ unsigned int val;
+
+ pmc_read(reg, AT91_PMC_SR, &val);
+
+ return !!(val & AT91_PMC_MOSCSELS);
+}
+
+static int clk_sam9x5_main_enable(struct clk *clk)
+{
+ struct clk_main *main = to_clk_main(clk);
+ void __iomem *reg = main->reg;
+
+ while (!clk_sam9x5_main_ready(reg)) {
+ debug("waiting for main...");
+ cpu_relax();
+ }
+
+ return clk_main_probe_frequency(reg);
+}
+
+static int clk_sam9x5_main_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct clk_main *main = to_clk_main(clk);
+ void __iomem *reg = main->reg;
+ unsigned int tmp, index;
+
+ index = at91_clk_mux_val_to_index(main->clk_mux_table,
+ main->num_parents, AT91_CLK_ID_TO_DID(parent->id));
+ if (index < 0)
+ return index;
+
+ pmc_read(reg, AT91_CKGR_MOR, &tmp);
+ tmp &= ~MOR_KEY_MASK;
+ tmp |= AT91_PMC_KEY;
+
+ if (index && !(tmp & AT91_PMC_MOSCSEL))
+ pmc_write(reg, AT91_CKGR_MOR, tmp | AT91_PMC_MOSCSEL);
+ else if (!index && (tmp & AT91_PMC_MOSCSEL))
+ pmc_write(reg, AT91_CKGR_MOR, tmp & ~AT91_PMC_MOSCSEL);
+
+ while (!clk_sam9x5_main_ready(reg))
+ cpu_relax();
+
+ return 0;
+}
+
+static const struct clk_ops sam9x5_main_clk_ops = {
+ .enable = clk_sam9x5_main_enable,
+ .set_parent = clk_sam9x5_main_set_parent,
+ .get_rate = clk_generic_get_rate,
+};
+
+struct clk *at91_clk_sam9x5_main(void __iomem *reg, const char *name,
+ const char * const *parent_names,
+ int num_parents, const u32 *clk_mux_table,
+ int type)
+{
+ struct clk *clk = ERR_PTR(-ENOMEM);
+ struct clk_main *main = NULL;
+ unsigned int val;
+ int ret;
+
+ if (!reg || !name || !parent_names || !num_parents || !clk_mux_table)
+ return ERR_PTR(-EINVAL);
+
+ main = kzalloc(sizeof(*main), GFP_KERNEL);
+ if (!main)
+ return ERR_PTR(-ENOMEM);
+
+ main->reg = reg;
+ main->parent_names = parent_names;
+ main->num_parents = num_parents;
+ main->clk_mux_table = clk_mux_table;
+ main->type = type;
+ clk = &main->clk;
+ clk->flags = CLK_GET_RATE_NOCACHE;
+ pmc_read(reg, AT91_CKGR_MOR, &val);
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAM9X5_MAIN, name,
+ main->parent_names[clk_main_parent_select(val)]);
+ if (ret) {
+ kfree(main);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(at91_sam9x5_main_clk) = {
+ .name = UBOOT_DM_CLK_AT91_SAM9X5_MAIN,
+ .id = UCLASS_CLK,
+ .ops = &sam9x5_main_clk_ops,
+ .flags = DM_FLAG_PRE_RELOC,
};
diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c
index e078fab7b41..759df93697d 100644
--- a/drivers/clk/at91/clk-master.c
+++ b/drivers/clk/at91/clk-master.c
@@ -1,33 +1,332 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2016 Atmel Corporation
- * Wenyou.Yang <wenyou.yang@atmel.com>
+ * Master clock support for AT91 architectures.
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ *
+ * Based on drivers/clk/at91/clk-master.c from Linux.
*/
-#include <common.h>
+#include <asm/processor.h>
#include <clk-uclass.h>
+#include <common.h>
#include <dm.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/at91_pmc.h>
+
+#include "pmc.h"
+
+#define UBOOT_DM_CLK_AT91_MASTER "at91-master-clk"
+#define UBOOT_DM_CLK_AT91_SAMA7G5_MASTER "at91-sama7g5-master-clk"
+
+#define MASTER_PRES_MASK 0x7
+#define MASTER_PRES_MAX MASTER_PRES_MASK
+#define MASTER_DIV_SHIFT 8
+#define MASTER_DIV_MASK 0x3
+
+#define PMC_MCR 0x30
+#define PMC_MCR_ID_MSK GENMASK(3, 0)
+#define PMC_MCR_CMD BIT(7)
+#define PMC_MCR_DIV GENMASK(10, 8)
+#define PMC_MCR_CSS GENMASK(20, 16)
+#define PMC_MCR_CSS_SHIFT (16)
+#define PMC_MCR_EN BIT(28)
+
+#define PMC_MCR_ID(x) ((x) & PMC_MCR_ID_MSK)
+
+#define MASTER_MAX_ID 4
+
+struct clk_master {
+ void __iomem *base;
+ const struct clk_master_layout *layout;
+ const struct clk_master_characteristics *characteristics;
+ const u32 *mux_table;
+ const u32 *clk_mux_table;
+ u32 num_parents;
+ struct clk clk;
+ u8 id;
+};
+
+#define to_clk_master(_clk) container_of(_clk, struct clk_master, clk)
+
+static inline bool clk_master_ready(struct clk_master *master)
+{
+ unsigned int bit = master->id ? AT91_PMC_MCKXRDY : AT91_PMC_MCKRDY;
+ unsigned int status;
+
+ pmc_read(master->base, AT91_PMC_SR, &status);
+
+ return !!(status & bit);
+}
+
+static int clk_master_enable(struct clk *clk)
+{
+ struct clk_master *master = to_clk_master(clk);
+
+ while (!clk_master_ready(master)) {
+ debug("waiting for mck %d\n", master->id);
+ cpu_relax();
+ }
+
+ return 0;
+}
-DECLARE_GLOBAL_DATA_PTR;
+static ulong clk_master_get_rate(struct clk *clk)
+{
+ struct clk_master *master = to_clk_master(clk);
+ const struct clk_master_layout *layout = master->layout;
+ const struct clk_master_characteristics *characteristics =
+ master->characteristics;
+ ulong rate = clk_get_parent_rate(clk);
+ unsigned int mckr;
+ u8 pres, div;
+
+ if (!rate)
+ return 0;
+
+ pmc_read(master->base, master->layout->offset, &mckr);
+ mckr &= layout->mask;
+
+ pres = (mckr >> layout->pres_shift) & MASTER_PRES_MASK;
+ div = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
+
+ if (characteristics->have_div3_pres && pres == MASTER_PRES_MAX)
+ rate /= 3;
+ else
+ rate >>= pres;
+
+ rate /= characteristics->divisors[div];
+
+ if (rate < characteristics->output.min)
+ pr_warn("master clk is underclocked");
+ else if (rate > characteristics->output.max)
+ pr_warn("master clk is overclocked");
+
+ return rate;
+}
+
+static const struct clk_ops master_ops = {
+ .enable = clk_master_enable,
+ .get_rate = clk_master_get_rate,
+};
-static ulong at91_master_clk_get_rate(struct clk *clk)
+struct clk *at91_clk_register_master(void __iomem *base,
+ const char *name, const char * const *parent_names,
+ int num_parents, const struct clk_master_layout *layout,
+ const struct clk_master_characteristics *characteristics,
+ const u32 *mux_table)
{
- return gd->arch.mck_rate_hz;
+ struct clk_master *master;
+ struct clk *clk;
+ unsigned int val;
+ int ret;
+
+ if (!base || !name || !num_parents || !parent_names ||
+ !layout || !characteristics || !mux_table)
+ return ERR_PTR(-EINVAL);
+
+ master = kzalloc(sizeof(*master), GFP_KERNEL);
+ if (!master)
+ return ERR_PTR(-ENOMEM);
+
+ master->layout = layout;
+ master->characteristics = characteristics;
+ master->base = base;
+ master->num_parents = num_parents;
+ master->mux_table = mux_table;
+
+ pmc_read(master->base, master->layout->offset, &val);
+ clk = &master->clk;
+ clk->flags = CLK_GET_RATE_NOCACHE | CLK_IS_CRITICAL;
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_MASTER, name,
+ parent_names[val & AT91_PMC_CSS]);
+ if (ret) {
+ kfree(master);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
}
-static struct clk_ops at91_master_clk_ops = {
- .get_rate = at91_master_clk_get_rate,
+U_BOOT_DRIVER(at91_master_clk) = {
+ .name = UBOOT_DM_CLK_AT91_MASTER,
+ .id = UCLASS_CLK,
+ .ops = &master_ops,
+ .flags = DM_FLAG_PRE_RELOC,
};
-static const struct udevice_id at91_master_clk_match[] = {
- { .compatible = "atmel,at91rm9200-clk-master" },
- { .compatible = "atmel,at91sam9x5-clk-master" },
- {}
+static int clk_sama7g5_master_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct clk_master *master = to_clk_master(clk);
+ int index;
+
+ index = at91_clk_mux_val_to_index(master->clk_mux_table,
+ master->num_parents, parent->id);
+ if (index < 0)
+ return index;
+
+ index = at91_clk_mux_index_to_val(master->mux_table,
+ master->num_parents, index);
+ if (index < 0)
+ return index;
+
+ pmc_write(master->base, PMC_MCR, PMC_MCR_ID(master->id));
+ pmc_update_bits(master->base, PMC_MCR,
+ PMC_MCR_CSS | PMC_MCR_CMD | PMC_MCR_ID_MSK,
+ (index << PMC_MCR_CSS_SHIFT) | PMC_MCR_CMD |
+ PMC_MCR_ID(master->id));
+ return 0;
+}
+
+static int clk_sama7g5_master_enable(struct clk *clk)
+{
+ struct clk_master *master = to_clk_master(clk);
+
+ pmc_write(master->base, PMC_MCR, PMC_MCR_ID(master->id));
+ pmc_update_bits(master->base, PMC_MCR,
+ PMC_MCR_EN | PMC_MCR_CMD | PMC_MCR_ID_MSK,
+ PMC_MCR_EN | PMC_MCR_CMD | PMC_MCR_ID(master->id));
+
+ return 0;
+}
+
+static int clk_sama7g5_master_disable(struct clk *clk)
+{
+ struct clk_master *master = to_clk_master(clk);
+
+ pmc_write(master->base, PMC_MCR, master->id);
+ pmc_update_bits(master->base, PMC_MCR,
+ PMC_MCR_EN | PMC_MCR_CMD | PMC_MCR_ID_MSK,
+ PMC_MCR_CMD | PMC_MCR_ID(master->id));
+
+ return 0;
+}
+
+static ulong clk_sama7g5_master_set_rate(struct clk *clk, ulong rate)
+{
+ struct clk_master *master = to_clk_master(clk);
+ ulong parent_rate = clk_get_parent_rate(clk);
+ ulong div, rrate;
+
+ if (!parent_rate)
+ return 0;
+
+ div = DIV_ROUND_CLOSEST(parent_rate, rate);
+ if ((div > (1 << (MASTER_PRES_MAX - 1))) || (div & (div - 1))) {
+ return 0;
+ } else if (div == 3) {
+ rrate = DIV_ROUND_CLOSEST(parent_rate, MASTER_PRES_MAX);
+ div = MASTER_PRES_MAX;
+ } else {
+ rrate = DIV_ROUND_CLOSEST(parent_rate, div);
+ div = ffs(div) - 1;
+ }
+
+ pmc_write(master->base, PMC_MCR, master->id);
+ pmc_update_bits(master->base, PMC_MCR,
+ PMC_MCR_DIV | PMC_MCR_CMD | PMC_MCR_ID_MSK,
+ (div << MASTER_DIV_SHIFT) | PMC_MCR_CMD |
+ PMC_MCR_ID(master->id));
+
+ return rrate;
+}
+
+static ulong clk_sama7g5_master_get_rate(struct clk *clk)
+{
+ struct clk_master *master = to_clk_master(clk);
+ ulong parent_rate = clk_get_parent_rate(clk);
+ unsigned int val;
+ ulong div;
+
+ if (!parent_rate)
+ return 0;
+
+ pmc_write(master->base, PMC_MCR, master->id);
+ pmc_read(master->base, PMC_MCR, &val);
+
+ div = (val >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
+
+ if (div == MASTER_PRES_MAX)
+ div = 3;
+ else
+ div = 1 << div;
+
+ return DIV_ROUND_CLOSEST(parent_rate, div);
+}
+
+static const struct clk_ops sama7g5_master_ops = {
+ .enable = clk_sama7g5_master_enable,
+ .disable = clk_sama7g5_master_disable,
+ .set_rate = clk_sama7g5_master_set_rate,
+ .get_rate = clk_sama7g5_master_get_rate,
+ .set_parent = clk_sama7g5_master_set_parent,
};
-U_BOOT_DRIVER(atmel_at91rm9200_clk_master) = {
- .name = "atmel_at91rm9200_clk_master",
+struct clk *at91_clk_sama7g5_register_master(void __iomem *base,
+ const char *name, const char * const *parent_names,
+ int num_parents, const u32 *mux_table, const u32 *clk_mux_table,
+ bool critical, u8 id)
+{
+ struct clk_master *master;
+ struct clk *clk;
+ u32 val, index;
+ int ret;
+
+ if (!base || !name || !num_parents || !parent_names ||
+ !mux_table || !clk_mux_table || id > MASTER_MAX_ID)
+ return ERR_PTR(-EINVAL);
+
+ master = kzalloc(sizeof(*master), GFP_KERNEL);
+ if (!master)
+ return ERR_PTR(-ENOMEM);
+
+ master->base = base;
+ master->id = id;
+ master->mux_table = mux_table;
+ master->clk_mux_table = clk_mux_table;
+ master->num_parents = num_parents;
+
+ pmc_write(master->base, PMC_MCR, master->id);
+ pmc_read(master->base, PMC_MCR, &val);
+
+ index = at91_clk_mux_val_to_index(master->mux_table,
+ master->num_parents,
+ (val & PMC_MCR_CSS) >> PMC_MCR_CSS_SHIFT);
+ if (index < 0) {
+ kfree(master);
+ return ERR_PTR(index);
+ }
+
+ clk = &master->clk;
+ clk->flags = CLK_GET_RATE_NOCACHE | (critical ? CLK_IS_CRITICAL : 0);
+
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAMA7G5_MASTER, name,
+ parent_names[index]);
+ if (ret) {
+ kfree(master);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(at91_sama7g5_master_clk) = {
+ .name = UBOOT_DM_CLK_AT91_SAMA7G5_MASTER,
.id = UCLASS_CLK,
- .of_match = at91_master_clk_match,
- .ops = &at91_master_clk_ops,
+ .ops = &sama7g5_master_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+const struct clk_master_layout at91rm9200_master_layout = {
+ .mask = 0x31F,
+ .pres_shift = 2,
+ .offset = AT91_PMC_MCKR,
+};
+
+const struct clk_master_layout at91sam9x5_master_layout = {
+ .mask = 0x373,
+ .pres_shift = 4,
+ .offset = AT91_PMC_MCKR,
};
diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c
index cd9d5e77c02..52cbc520cef 100644
--- a/drivers/clk/at91/clk-peripheral.c
+++ b/drivers/clk/at91/clk-peripheral.c
@@ -1,113 +1,254 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2016 Atmel Corporation
- * Wenyou.Yang <wenyou.yang@atmel.com>
+ * Peripheral clock support for AT91 architectures.
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ *
+ * Based on drivers/clk/at91/clk-peripheral.c from Linux.
*/
-
#include <common.h>
#include <clk-uclass.h>
#include <dm.h>
-#include <malloc.h>
#include <linux/io.h>
-#include <mach/at91_pmc.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/at91_pmc.h>
+
#include "pmc.h"
+#define UBOOT_DM_CLK_AT91_PERIPH "at91-periph-clk"
+#define UBOOT_DM_CLK_AT91_SAM9X5_PERIPH "at91-sam9x5-periph-clk"
+
#define PERIPHERAL_ID_MIN 2
#define PERIPHERAL_ID_MAX 31
#define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX))
-enum periph_clk_type {
- CLK_PERIPH_AT91RM9200 = 0,
- CLK_PERIPH_AT91SAM9X5,
+#define PERIPHERAL_MAX_SHIFT 3
+
+struct clk_peripheral {
+ void __iomem *base;
+ struct clk clk;
+ u32 id;
};
-/**
- * sam9x5_periph_clk_bind() - for the periph clock driver
- * Recursively bind its children as clk devices.
- *
- * @return: 0 on success, or negative error code on failure
- */
-static int sam9x5_periph_clk_bind(struct udevice *dev)
+
+#define to_clk_peripheral(_c) container_of(_c, struct clk_peripheral, clk)
+
+struct clk_sam9x5_peripheral {
+ const struct clk_pcr_layout *layout;
+ void __iomem *base;
+ struct clk clk;
+ struct clk_range range;
+ u32 id;
+ u32 div;
+ bool auto_div;
+};
+
+#define to_clk_sam9x5_peripheral(_c) \
+ container_of(_c, struct clk_sam9x5_peripheral, clk)
+
+static int clk_peripheral_enable(struct clk *clk)
{
- return at91_clk_sub_device_bind(dev, "periph-clk");
+ struct clk_peripheral *periph = to_clk_peripheral(clk);
+ int offset = AT91_PMC_PCER;
+ u32 id = periph->id;
+
+ if (id < PERIPHERAL_ID_MIN)
+ return 0;
+ if (id > PERIPHERAL_ID_MAX)
+ offset = AT91_PMC_PCER1;
+ pmc_write(periph->base, offset, PERIPHERAL_MASK(id));
+
+ return 0;
+}
+
+static int clk_peripheral_disable(struct clk *clk)
+{
+ struct clk_peripheral *periph = to_clk_peripheral(clk);
+ int offset = AT91_PMC_PCDR;
+ u32 id = periph->id;
+
+ if (id < PERIPHERAL_ID_MIN)
+ return -EINVAL;
+
+ if (id > PERIPHERAL_ID_MAX)
+ offset = AT91_PMC_PCDR1;
+ pmc_write(periph->base, offset, PERIPHERAL_MASK(id));
+
+ return 0;
}
-static const struct udevice_id sam9x5_periph_clk_match[] = {
- {
- .compatible = "atmel,at91rm9200-clk-peripheral",
- .data = CLK_PERIPH_AT91RM9200,
- },
- {
- .compatible = "atmel,at91sam9x5-clk-peripheral",
- .data = CLK_PERIPH_AT91SAM9X5,
- },
- {}
+static const struct clk_ops peripheral_ops = {
+ .enable = clk_peripheral_enable,
+ .disable = clk_peripheral_disable,
+ .get_rate = clk_generic_get_rate,
};
-U_BOOT_DRIVER(atmel_at91rm9200_clk_peripheral) = {
- .name = "atmel_at91rm9200_clk_peripheral",
- .id = UCLASS_MISC,
- .of_match = sam9x5_periph_clk_match,
- .bind = sam9x5_periph_clk_bind,
+struct clk *
+at91_clk_register_peripheral(void __iomem *base, const char *name,
+ const char *parent_name, u32 id)
+{
+ struct clk_peripheral *periph;
+ struct clk *clk;
+ int ret;
+
+ if (!base || !name || !parent_name || id > PERIPHERAL_ID_MAX)
+ return ERR_PTR(-EINVAL);
+
+ periph = kzalloc(sizeof(*periph), GFP_KERNEL);
+ if (!periph)
+ return ERR_PTR(-ENOMEM);
+
+ periph->id = id;
+ periph->base = base;
+
+ clk = &periph->clk;
+ clk->flags = CLK_GET_RATE_NOCACHE;
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_PERIPH, name, parent_name);
+ if (ret) {
+ kfree(periph);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(at91_periph_clk) = {
+ .name = UBOOT_DM_CLK_AT91_PERIPH,
+ .id = UCLASS_CLK,
+ .ops = &peripheral_ops,
+ .flags = DM_FLAG_PRE_RELOC,
};
-/*---------------------------------------------------------*/
+static int clk_sam9x5_peripheral_enable(struct clk *clk)
+{
+ struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(clk);
+
+ if (periph->id < PERIPHERAL_ID_MIN)
+ return 0;
+
+ pmc_write(periph->base, periph->layout->offset,
+ (periph->id & periph->layout->pid_mask));
+ pmc_update_bits(periph->base, periph->layout->offset,
+ periph->layout->cmd | AT91_PMC_PCR_EN,
+ periph->layout->cmd | AT91_PMC_PCR_EN);
-static int periph_clk_enable(struct clk *clk)
+ return 0;
+}
+
+static int clk_sam9x5_peripheral_disable(struct clk *clk)
{
- struct pmc_platdata *plat = dev_get_platdata(clk->dev);
- struct at91_pmc *pmc = plat->reg_base;
- enum periph_clk_type clk_type;
- void *addr;
-
- if (clk->id < PERIPHERAL_ID_MIN)
- return -1;
-
- clk_type = dev_get_driver_data(dev_get_parent(clk->dev));
- if (clk_type == CLK_PERIPH_AT91RM9200) {
- addr = &pmc->pcer;
- if (clk->id > PERIPHERAL_ID_MAX)
- addr = &pmc->pcer1;
-
- setbits_le32(addr, PERIPHERAL_MASK(clk->id));
- } else {
- writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr);
- setbits_le32(&pmc->pcr,
- AT91_PMC_PCR_CMD_WRITE | AT91_PMC_PCR_EN);
- }
+ struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(clk);
+
+ if (periph->id < PERIPHERAL_ID_MIN)
+ return -EINVAL;
+
+ pmc_write(periph->base, periph->layout->offset,
+ (periph->id & periph->layout->pid_mask));
+ pmc_update_bits(periph->base, periph->layout->offset,
+ AT91_PMC_PCR_EN | periph->layout->cmd,
+ periph->layout->cmd);
return 0;
}
-static ulong periph_get_rate(struct clk *clk)
+static ulong clk_sam9x5_peripheral_get_rate(struct clk *clk)
{
- struct udevice *dev;
- struct clk clk_dev;
- ulong clk_rate;
- int ret;
+ struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(clk);
+ ulong parent_rate = clk_get_parent_rate(clk);
+ u32 val, shift = ffs(periph->layout->div_mask) - 1;
- dev = dev_get_parent(clk->dev);
+ if (!parent_rate)
+ return 0;
- ret = clk_get_by_index(dev, 0, &clk_dev);
- if (ret)
- return ret;
+ pmc_write(periph->base, periph->layout->offset,
+ (periph->id & periph->layout->pid_mask));
+ pmc_read(periph->base, periph->layout->offset, &val);
+ shift = (val & periph->layout->div_mask) >> shift;
- clk_rate = clk_get_rate(&clk_dev);
+ return parent_rate >> shift;
+}
+
+static ulong clk_sam9x5_peripheral_set_rate(struct clk *clk, ulong rate)
+{
+ struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(clk);
+ ulong parent_rate = clk_get_parent_rate(clk);
+ int shift;
+
+ if (!parent_rate)
+ return 0;
+
+ if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max) {
+ if (parent_rate == rate)
+ return rate;
+ else
+ return 0;
+ }
+
+ if (periph->range.max && rate > periph->range.max)
+ return 0;
+
+ for (shift = 0; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
+ if (parent_rate >> shift <= rate)
+ break;
+ }
+ if (shift == PERIPHERAL_MAX_SHIFT + 1)
+ return 0;
- clk_free(&clk_dev);
+ pmc_write(periph->base, periph->layout->offset,
+ (periph->id & periph->layout->pid_mask));
+ pmc_update_bits(periph->base, periph->layout->offset,
+ periph->layout->div_mask | periph->layout->cmd,
+ (shift << (ffs(periph->layout->div_mask) - 1)) |
+ periph->layout->cmd);
- return clk_rate;
+ return parent_rate >> shift;
}
-static struct clk_ops periph_clk_ops = {
- .of_xlate = at91_clk_of_xlate,
- .enable = periph_clk_enable,
- .get_rate = periph_get_rate,
+static const struct clk_ops sam9x5_peripheral_ops = {
+ .enable = clk_sam9x5_peripheral_enable,
+ .disable = clk_sam9x5_peripheral_disable,
+ .get_rate = clk_sam9x5_peripheral_get_rate,
+ .set_rate = clk_sam9x5_peripheral_set_rate,
};
-U_BOOT_DRIVER(clk_periph) = {
- .name = "periph-clk",
- .id = UCLASS_CLK,
- .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
- .probe = at91_clk_probe,
- .ops = &periph_clk_ops,
+struct clk *
+at91_clk_register_sam9x5_peripheral(void __iomem *base,
+ const struct clk_pcr_layout *layout,
+ const char *name, const char *parent_name,
+ u32 id, const struct clk_range *range)
+{
+ struct clk_sam9x5_peripheral *periph;
+ struct clk *clk;
+ int ret;
+
+ if (!base || !layout || !name || !parent_name || !range)
+ return ERR_PTR(-EINVAL);
+
+ periph = kzalloc(sizeof(*periph), GFP_KERNEL);
+ if (!periph)
+ return ERR_PTR(-ENOMEM);
+
+ periph->id = id;
+ periph->base = base;
+ periph->layout = layout;
+ periph->range = *range;
+
+ clk = &periph->clk;
+ clk->flags = CLK_GET_RATE_NOCACHE;
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAM9X5_PERIPH, name,
+ parent_name);
+ if (ret) {
+ kfree(periph);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(at91_sam9x5_periph_clk) = {
+ .name = UBOOT_DM_CLK_AT91_SAM9X5_PERIPH,
+ .id = UCLASS_CLK,
+ .ops = &sam9x5_peripheral_ops,
+ .flags = DM_FLAG_PRE_RELOC,
};
diff --git a/drivers/clk/at91/clk-plla.c b/drivers/clk/at91/clk-plla.c
deleted file mode 100644
index 79d725819fc..00000000000
--- a/drivers/clk/at91/clk-plla.c
+++ /dev/null
@@ -1,54 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2016 Atmel Corporation
- * Wenyou.Yang <wenyou.yang@atmel.com>
- */
-
-#include <common.h>
-#include <clk-uclass.h>
-#include <dm.h>
-#include <linux/io.h>
-#include <mach/at91_pmc.h>
-#include "pmc.h"
-
-DECLARE_GLOBAL_DATA_PTR;
-
-static int plla_clk_enable(struct clk *clk)
-{
- struct pmc_platdata *plat = dev_get_platdata(clk->dev);
- struct at91_pmc *pmc = plat->reg_base;
-
- if (readl(&pmc->sr) & AT91_PMC_LOCKA)
- return 0;
-
- return -EINVAL;
-}
-
-static ulong plla_clk_get_rate(struct clk *clk)
-{
- return gd->arch.plla_rate_hz;
-}
-
-static struct clk_ops plla_clk_ops = {
- .enable = plla_clk_enable,
- .get_rate = plla_clk_get_rate,
-};
-
-static int plla_clk_probe(struct udevice *dev)
-{
- return at91_pmc_core_probe(dev);
-}
-
-static const struct udevice_id plla_clk_match[] = {
- { .compatible = "atmel,sama5d3-clk-pll" },
- {}
-};
-
-U_BOOT_DRIVER(at91_plla_clk) = {
- .name = "at91-plla-clk",
- .id = UCLASS_CLK,
- .of_match = plla_clk_match,
- .probe = plla_clk_probe,
- .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
- .ops = &plla_clk_ops,
-};
diff --git a/drivers/clk/at91/clk-plladiv.c b/drivers/clk/at91/clk-plladiv.c
deleted file mode 100644
index ca6158ef6ab..00000000000
--- a/drivers/clk/at91/clk-plladiv.c
+++ /dev/null
@@ -1,85 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2018 Microhip / Atmel Corporation
- * Wenyou.Yang <wenyou.yang@microchip.com>
- */
-
-#include <common.h>
-#include <clk-uclass.h>
-#include <dm/device.h>
-#include <linux/io.h>
-#include <mach/at91_pmc.h>
-#include "pmc.h"
-
-static int at91_plladiv_clk_enable(struct clk *clk)
-{
- return 0;
-}
-
-static ulong at91_plladiv_clk_get_rate(struct clk *clk)
-{
- struct pmc_platdata *plat = dev_get_platdata(clk->dev);
- struct at91_pmc *pmc = plat->reg_base;
- struct clk source;
- ulong clk_rate;
- int ret;
-
- ret = clk_get_by_index(clk->dev, 0, &source);
- if (ret)
- return -EINVAL;
-
- clk_rate = clk_get_rate(&source);
- if (readl(&pmc->mckr) & AT91_PMC_MCKR_PLLADIV_2)
- clk_rate /= 2;
-
- return clk_rate;
-}
-
-static ulong at91_plladiv_clk_set_rate(struct clk *clk, ulong rate)
-{
- struct pmc_platdata *plat = dev_get_platdata(clk->dev);
- struct at91_pmc *pmc = plat->reg_base;
- struct clk source;
- ulong parent_rate;
- int ret;
-
- ret = clk_get_by_index(clk->dev, 0, &source);
- if (ret)
- return -EINVAL;
-
- parent_rate = clk_get_rate(&source);
- if ((parent_rate != rate) && ((parent_rate) / 2 != rate))
- return -EINVAL;
-
- if (parent_rate != rate) {
- writel((readl(&pmc->mckr) | AT91_PMC_MCKR_PLLADIV_2),
- &pmc->mckr);
- }
-
- return 0;
-}
-
-static struct clk_ops at91_plladiv_clk_ops = {
- .enable = at91_plladiv_clk_enable,
- .get_rate = at91_plladiv_clk_get_rate,
- .set_rate = at91_plladiv_clk_set_rate,
-};
-
-static int at91_plladiv_clk_probe(struct udevice *dev)
-{
- return at91_pmc_core_probe(dev);
-}
-
-static const struct udevice_id at91_plladiv_clk_match[] = {
- { .compatible = "atmel,at91sam9x5-clk-plldiv" },
- {}
-};
-
-U_BOOT_DRIVER(at91_plladiv_clk) = {
- .name = "at91-plladiv-clk",
- .id = UCLASS_CLK,
- .of_match = at91_plladiv_clk_match,
- .probe = at91_plladiv_clk_probe,
- .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
- .ops = &at91_plladiv_clk_ops,
-};
diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c
new file mode 100644
index 00000000000..868de4b1774
--- /dev/null
+++ b/drivers/clk/at91/clk-programmable.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Programmable clock support for AT91 architectures.
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ *
+ * Based on drivers/clk/at91/clk-programmable.c from Linux.
+ */
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/at91_pmc.h>
+
+#include "pmc.h"
+
+#define UBOOT_DM_CLK_AT91_PROG "at91-prog-clk"
+
+#define PROG_ID_MAX 7
+
+#define PROG_STATUS_MASK(id) (1 << ((id) + 8))
+#define PROG_PRES(_l, _p) (((_p) >> (_l)->pres_shift) & (_l)->pres_mask)
+#define PROG_MAX_RM9200_CSS 3
+
+struct clk_programmable {
+ void __iomem *base;
+ const u32 *clk_mux_table;
+ const u32 *mux_table;
+ const struct clk_programmable_layout *layout;
+ u32 num_parents;
+ struct clk clk;
+ u8 id;
+};
+
+#define to_clk_programmable(_c) container_of(_c, struct clk_programmable, clk)
+
+static ulong clk_programmable_get_rate(struct clk *clk)
+{
+ struct clk_programmable *prog = to_clk_programmable(clk);
+ const struct clk_programmable_layout *layout = prog->layout;
+ ulong rate, parent_rate = clk_get_parent_rate(clk);
+ unsigned int pckr;
+
+ pmc_read(prog->base, AT91_PMC_PCKR(prog->id), &pckr);
+
+ if (layout->is_pres_direct)
+ rate = parent_rate / (PROG_PRES(layout, pckr) + 1);
+ else
+ rate = parent_rate >> PROG_PRES(layout, pckr);
+
+ return rate;
+}
+
+static int clk_programmable_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct clk_programmable *prog = to_clk_programmable(clk);
+ const struct clk_programmable_layout *layout = prog->layout;
+ unsigned int mask = layout->css_mask;
+ int index;
+
+ index = at91_clk_mux_val_to_index(prog->clk_mux_table,
+ prog->num_parents, parent->id);
+ if (index < 0)
+ return index;
+
+ index = at91_clk_mux_index_to_val(prog->mux_table, prog->num_parents,
+ index);
+ if (index < 0)
+ return index;
+
+ if (layout->have_slck_mck)
+ mask |= AT91_PMC_CSSMCK_MCK;
+
+ if (index > layout->css_mask) {
+ if (index > PROG_MAX_RM9200_CSS && !layout->have_slck_mck)
+ return -EINVAL;
+
+ index |= AT91_PMC_CSSMCK_MCK;
+ }
+
+ pmc_update_bits(prog->base, AT91_PMC_PCKR(prog->id), mask, index);
+
+ return 0;
+}
+
+static ulong clk_programmable_set_rate(struct clk *clk, ulong rate)
+{
+ struct clk_programmable *prog = to_clk_programmable(clk);
+ const struct clk_programmable_layout *layout = prog->layout;
+ ulong parent_rate = clk_get_parent_rate(clk);
+ ulong div = parent_rate / rate;
+ int shift = 0;
+
+ if (!parent_rate || !div)
+ return -EINVAL;
+
+ if (layout->is_pres_direct) {
+ shift = div - 1;
+
+ if (shift > layout->pres_mask)
+ return -EINVAL;
+ } else {
+ shift = fls(div) - 1;
+
+ if (div != (1 << shift))
+ return -EINVAL;
+
+ if (shift >= layout->pres_mask)
+ return -EINVAL;
+ }
+
+ pmc_update_bits(prog->base, AT91_PMC_PCKR(prog->id),
+ layout->pres_mask << layout->pres_shift,
+ shift << layout->pres_shift);
+
+ if (layout->is_pres_direct)
+ return (parent_rate / shift + 1);
+
+ return parent_rate >> shift;
+}
+
+static const struct clk_ops programmable_ops = {
+ .get_rate = clk_programmable_get_rate,
+ .set_parent = clk_programmable_set_parent,
+ .set_rate = clk_programmable_set_rate,
+};
+
+struct clk *at91_clk_register_programmable(void __iomem *base, const char *name,
+ const char *const *parent_names, u8 num_parents, u8 id,
+ const struct clk_programmable_layout *layout,
+ const u32 *clk_mux_table, const u32 *mux_table)
+{
+ struct clk_programmable *prog;
+ struct clk *clk;
+ u32 val, tmp;
+ int ret;
+
+ if (!base || !name || !parent_names || !num_parents ||
+ !layout || !clk_mux_table || !mux_table || id > PROG_ID_MAX)
+ return ERR_PTR(-EINVAL);
+
+ prog = kzalloc(sizeof(*prog), GFP_KERNEL);
+ if (!prog)
+ return ERR_PTR(-ENOMEM);
+
+ prog->id = id;
+ prog->layout = layout;
+ prog->base = base;
+ prog->clk_mux_table = clk_mux_table;
+ prog->mux_table = mux_table;
+ prog->num_parents = num_parents;
+
+ pmc_read(prog->base, AT91_PMC_PCKR(prog->id), &tmp);
+ val = tmp & prog->layout->css_mask;
+ if (layout->have_slck_mck && (tmp & AT91_PMC_CSSMCK_MCK) && !val)
+ ret = PROG_MAX_RM9200_CSS + 1;
+ else
+ ret = at91_clk_mux_val_to_index(prog->mux_table,
+ prog->num_parents, val);
+ if (ret < 0) {
+ kfree(prog);
+ return ERR_PTR(ret);
+ }
+
+ clk = &prog->clk;
+ clk->flags = CLK_GET_RATE_NOCACHE;
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_PROG, name,
+ parent_names[ret]);
+ if (ret) {
+ kfree(prog);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(at91_prog_clk) = {
+ .name = UBOOT_DM_CLK_AT91_PROG,
+ .id = UCLASS_CLK,
+ .ops = &programmable_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+const struct clk_programmable_layout at91rm9200_programmable_layout = {
+ .pres_mask = 0x7,
+ .pres_shift = 2,
+ .css_mask = 0x3,
+ .have_slck_mck = 0,
+ .is_pres_direct = 0,
+};
+
+const struct clk_programmable_layout at91sam9g45_programmable_layout = {
+ .pres_mask = 0x7,
+ .pres_shift = 2,
+ .css_mask = 0x3,
+ .have_slck_mck = 1,
+ .is_pres_direct = 0,
+};
+
+const struct clk_programmable_layout at91sam9x5_programmable_layout = {
+ .pres_mask = 0x7,
+ .pres_shift = 4,
+ .css_mask = 0x7,
+ .have_slck_mck = 0,
+ .is_pres_direct = 0,
+};
diff --git a/drivers/clk/at91/clk-sam9x60-pll.c b/drivers/clk/at91/clk-sam9x60-pll.c
new file mode 100644
index 00000000000..1bfae5fd016
--- /dev/null
+++ b/drivers/clk/at91/clk-sam9x60-pll.c
@@ -0,0 +1,442 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * SAM9X60's PLL clock support.
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ *
+ * Based on drivers/clk/at91/clk-sam9x60-pll.c from Linux.
+ *
+ */
+
+#include <asm/processor.h>
+#include <common.h>
+#include <clk-uclass.h>
+#include <div64.h>
+#include <dm.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/at91_pmc.h>
+#include <linux/delay.h>
+
+#include "pmc.h"
+
+#define UBOOT_DM_CLK_AT91_SAM9X60_DIV_PLL "at91-sam9x60-div-pll-clk"
+#define UBOOT_DM_CLK_AT91_SAM9X60_FRAC_PLL "at91-sam9x60-frac-pll-clk"
+
+#define PMC_PLL_CTRL0_DIV_MSK GENMASK(7, 0)
+#define PMC_PLL_CTRL1_MUL_MSK GENMASK(31, 24)
+#define PMC_PLL_CTRL1_FRACR_MSK GENMASK(21, 0)
+
+#define PLL_DIV_MAX (FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, UINT_MAX) + 1)
+#define UPLL_DIV 2
+#define PLL_MUL_MAX (FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, UINT_MAX) + 1)
+
+#define FCORE_MIN (600000000)
+#define FCORE_MAX (1200000000)
+
+#define PLL_MAX_ID 7
+
+struct sam9x60_pll {
+ void __iomem *base;
+ const struct clk_pll_characteristics *characteristics;
+ const struct clk_pll_layout *layout;
+ struct clk clk;
+ u8 id;
+};
+
+#define to_sam9x60_pll(_clk) container_of(_clk, struct sam9x60_pll, clk)
+
+static inline bool sam9x60_pll_ready(void __iomem *base, int id)
+{
+ unsigned int status;
+
+ pmc_read(base, AT91_PMC_PLL_ISR0, &status);
+
+ return !!(status & BIT(id));
+}
+
+static long sam9x60_frac_pll_compute_mul_frac(u32 *mul, u32 *frac, ulong rate,
+ ulong parent_rate)
+{
+ unsigned long tmprate, remainder;
+ unsigned long nmul = 0;
+ unsigned long nfrac = 0;
+
+ if (rate < FCORE_MIN || rate > FCORE_MAX)
+ return -ERANGE;
+
+ /*
+ * Calculate the multiplier associated with the current
+ * divider that provide the closest rate to the requested one.
+ */
+ nmul = mult_frac(rate, 1, parent_rate);
+ tmprate = mult_frac(parent_rate, nmul, 1);
+ remainder = rate - tmprate;
+
+ if (remainder) {
+ nfrac = DIV_ROUND_CLOSEST_ULL((u64)remainder * (1 << 22),
+ parent_rate);
+
+ tmprate += DIV_ROUND_CLOSEST_ULL((u64)nfrac * parent_rate,
+ (1 << 22));
+ }
+
+ /* Check if resulted rate is valid. */
+ if (tmprate < FCORE_MIN || tmprate > FCORE_MAX)
+ return -ERANGE;
+
+ *mul = nmul - 1;
+ *frac = nfrac;
+
+ return tmprate;
+}
+
+static ulong sam9x60_frac_pll_set_rate(struct clk *clk, ulong rate)
+{
+ struct sam9x60_pll *pll = to_sam9x60_pll(clk);
+ void __iomem *base = pll->base;
+ ulong parent_rate = clk_get_parent_rate(clk);
+ u32 nmul, cmul, nfrac, cfrac, val;
+ bool ready = sam9x60_pll_ready(base, pll->id);
+ long ret;
+
+ if (!parent_rate)
+ return 0;
+
+ ret = sam9x60_frac_pll_compute_mul_frac(&nmul, &nfrac, rate,
+ parent_rate);
+ if (ret < 0)
+ return 0;
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
+ pll->id);
+ pmc_read(base, AT91_PMC_PLL_CTRL1, &val);
+ cmul = (val & pll->layout->mul_mask) >> pll->layout->mul_shift;
+ cfrac = (val & pll->layout->frac_mask) >> pll->layout->frac_shift;
+
+ /* Check against current values. */
+ if (sam9x60_pll_ready(base, pll->id) &&
+ nmul == cmul && nfrac == cfrac)
+ return 0;
+
+ /* Update it to hardware. */
+ pmc_write(base, AT91_PMC_PLL_CTRL1,
+ (nmul << pll->layout->mul_shift) |
+ (nfrac << pll->layout->frac_shift));
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT,
+ AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
+ AT91_PMC_PLL_UPDT_UPDATE | pll->id);
+
+ while (ready && !sam9x60_pll_ready(base, pll->id)) {
+ debug("waiting for pll %u...\n", pll->id);
+ cpu_relax();
+ }
+
+ return parent_rate * (nmul + 1) + ((u64)parent_rate * nfrac >> 22);
+}
+
+static ulong sam9x60_frac_pll_get_rate(struct clk *clk)
+{
+ struct sam9x60_pll *pll = to_sam9x60_pll(clk);
+ void __iomem *base = pll->base;
+ ulong parent_rate = clk_get_parent_rate(clk);
+ u32 mul, frac, val;
+
+ if (!parent_rate)
+ return 0;
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
+ pll->id);
+ pmc_read(base, AT91_PMC_PLL_CTRL1, &val);
+ mul = (val & pll->layout->mul_mask) >> pll->layout->mul_shift;
+ frac = (val & pll->layout->frac_mask) >> pll->layout->frac_shift;
+
+ return (parent_rate * (mul + 1) + ((u64)parent_rate * frac >> 22));
+}
+
+static int sam9x60_frac_pll_enable(struct clk *clk)
+{
+ struct sam9x60_pll *pll = to_sam9x60_pll(clk);
+ void __iomem *base = pll->base;
+ unsigned int val;
+ ulong crate;
+
+ crate = sam9x60_frac_pll_get_rate(clk);
+ if (crate < FCORE_MIN || crate > FCORE_MAX)
+ return -ERANGE;
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
+ pll->id);
+ pmc_read(base, AT91_PMC_PLL_CTRL1, &val);
+
+ if (sam9x60_pll_ready(base, pll->id))
+ return 0;
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT,
+ AT91_PMC_PMM_UPDT_STUPTIM_MSK |
+ AT91_PMC_PLL_UPDT_ID_MSK,
+ AT91_PMC_PLL_UPDT_STUPTIM(0x3f) | pll->id);
+
+ /* Recommended value for AT91_PMC_PLL_ACR */
+ if (pll->characteristics->upll)
+ val = AT91_PMC_PLL_ACR_DEFAULT_UPLL;
+ else
+ val = AT91_PMC_PLL_ACR_DEFAULT_PLLA;
+ pmc_write(base, AT91_PMC_PLL_ACR, val);
+
+ if (pll->characteristics->upll) {
+ /* Enable the UTMI internal bandgap */
+ val |= AT91_PMC_PLL_ACR_UTMIBG;
+ pmc_write(base, AT91_PMC_PLL_ACR, val);
+
+ udelay(10);
+
+ /* Enable the UTMI internal regulator */
+ val |= AT91_PMC_PLL_ACR_UTMIVR;
+ pmc_write(base, AT91_PMC_PLL_ACR, val);
+
+ udelay(10);
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT,
+ AT91_PMC_PLL_UPDT_UPDATE |
+ AT91_PMC_PLL_UPDT_ID_MSK,
+ AT91_PMC_PLL_UPDT_UPDATE | pll->id);
+ }
+
+ pmc_update_bits(base, AT91_PMC_PLL_CTRL0,
+ AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL,
+ AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL);
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT,
+ AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
+ AT91_PMC_PLL_UPDT_UPDATE | pll->id);
+
+ while (!sam9x60_pll_ready(base, pll->id)) {
+ debug("waiting for pll %u...\n", pll->id);
+ cpu_relax();
+ }
+
+ return 0;
+}
+
+static int sam9x60_frac_pll_disable(struct clk *clk)
+{
+ struct sam9x60_pll *pll = to_sam9x60_pll(clk);
+ void __iomem *base = pll->base;
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
+ pll->id);
+
+ pmc_update_bits(base, AT91_PMC_PLL_CTRL0,
+ AT91_PMC_PLL_CTRL0_ENPLL, 0);
+
+ if (pll->characteristics->upll)
+ pmc_update_bits(base, AT91_PMC_PLL_ACR,
+ AT91_PMC_PLL_ACR_UTMIBG |
+ AT91_PMC_PLL_ACR_UTMIVR, 0);
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT,
+ AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
+ AT91_PMC_PLL_UPDT_UPDATE | pll->id);
+
+ return 0;
+}
+
+static const struct clk_ops sam9x60_frac_pll_ops = {
+ .enable = sam9x60_frac_pll_enable,
+ .disable = sam9x60_frac_pll_disable,
+ .set_rate = sam9x60_frac_pll_set_rate,
+ .get_rate = sam9x60_frac_pll_get_rate,
+};
+
+static int sam9x60_div_pll_enable(struct clk *clk)
+{
+ struct sam9x60_pll *pll = to_sam9x60_pll(clk);
+ void __iomem *base = pll->base;
+ unsigned int val;
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
+ pll->id);
+ pmc_read(base, AT91_PMC_PLL_CTRL0, &val);
+
+ /* Stop if enabled. */
+ if (val & pll->layout->endiv_mask)
+ return 0;
+
+ pmc_update_bits(base, AT91_PMC_PLL_CTRL0,
+ pll->layout->endiv_mask,
+ (1 << pll->layout->endiv_shift));
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT,
+ AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
+ AT91_PMC_PLL_UPDT_UPDATE | pll->id);
+
+ while (!sam9x60_pll_ready(base, pll->id)) {
+ debug("waiting for pll %u...\n", pll->id);
+ cpu_relax();
+ }
+
+ return 0;
+}
+
+static int sam9x60_div_pll_disable(struct clk *clk)
+{
+ struct sam9x60_pll *pll = to_sam9x60_pll(clk);
+ void __iomem *base = pll->base;
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
+ pll->id);
+
+ pmc_update_bits(base, AT91_PMC_PLL_CTRL0,
+ pll->layout->endiv_mask, 0);
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT,
+ AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
+ AT91_PMC_PLL_UPDT_UPDATE | pll->id);
+
+ return 0;
+}
+
+static ulong sam9x60_div_pll_set_rate(struct clk *clk, ulong rate)
+{
+ struct sam9x60_pll *pll = to_sam9x60_pll(clk);
+ void __iomem *base = pll->base;
+ const struct clk_pll_characteristics *characteristics =
+ pll->characteristics;
+ ulong parent_rate = clk_get_parent_rate(clk);
+ u8 div = DIV_ROUND_CLOSEST_ULL(parent_rate, rate) - 1;
+ ulong req_rate = parent_rate / (div + 1);
+ bool ready = sam9x60_pll_ready(base, pll->id);
+ u32 val;
+
+ if (!parent_rate || div > pll->layout->div_mask ||
+ req_rate < characteristics->output[0].min ||
+ req_rate > characteristics->output[0].max)
+ return 0;
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
+ pll->id);
+ pmc_read(base, AT91_PMC_PLL_CTRL0, &val);
+ /* Compare against current value. */
+ if (div == ((val & pll->layout->div_mask) >> pll->layout->div_shift))
+ return 0;
+
+ /* Update it to hardware. */
+ pmc_update_bits(base, AT91_PMC_PLL_CTRL0,
+ pll->layout->div_mask,
+ div << pll->layout->div_shift);
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT,
+ AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
+ AT91_PMC_PLL_UPDT_UPDATE | pll->id);
+
+ while (ready && !sam9x60_pll_ready(base, pll->id)) {
+ debug("waiting for pll %u...\n", pll->id);
+ cpu_relax();
+ }
+
+ return req_rate;
+}
+
+static ulong sam9x60_div_pll_get_rate(struct clk *clk)
+{
+ struct sam9x60_pll *pll = to_sam9x60_pll(clk);
+ void __iomem *base = pll->base;
+ ulong parent_rate = clk_get_parent_rate(clk);
+ u32 val;
+ u8 div;
+
+ if (!parent_rate)
+ return 0;
+
+ pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
+ pll->id);
+
+ pmc_read(base, AT91_PMC_PLL_CTRL0, &val);
+
+ div = (val & pll->layout->div_mask) >> pll->layout->div_shift;
+
+ return parent_rate / (div + 1);
+}
+
+static const struct clk_ops sam9x60_div_pll_ops = {
+ .enable = sam9x60_div_pll_enable,
+ .disable = sam9x60_div_pll_disable,
+ .set_rate = sam9x60_div_pll_set_rate,
+ .get_rate = sam9x60_div_pll_get_rate,
+};
+
+static struct clk *
+sam9x60_clk_register_pll(void __iomem *base, const char *type,
+ const char *name, const char *parent_name, u8 id,
+ const struct clk_pll_characteristics *characteristics,
+ const struct clk_pll_layout *layout, u32 flags)
+{
+ struct sam9x60_pll *pll;
+ struct clk *clk;
+ int ret;
+
+ if (!base || !type || !name || !parent_name || !characteristics ||
+ !layout || id > PLL_MAX_ID)
+ return ERR_PTR(-EINVAL);
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll)
+ return ERR_PTR(-ENOMEM);
+
+ pll->id = id;
+ pll->characteristics = characteristics;
+ pll->layout = layout;
+ pll->base = base;
+ clk = &pll->clk;
+ clk->flags = flags;
+
+ ret = clk_register(clk, type, name, parent_name);
+ if (ret) {
+ kfree(pll);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+struct clk *
+sam9x60_clk_register_div_pll(void __iomem *base, const char *name,
+ const char *parent_name, u8 id,
+ const struct clk_pll_characteristics *characteristics,
+ const struct clk_pll_layout *layout, bool critical)
+{
+ return sam9x60_clk_register_pll(base,
+ UBOOT_DM_CLK_AT91_SAM9X60_DIV_PLL, name, parent_name, id,
+ characteristics, layout,
+ CLK_GET_RATE_NOCACHE | (critical ? CLK_IS_CRITICAL : 0));
+}
+
+struct clk *
+sam9x60_clk_register_frac_pll(void __iomem *base, const char *name,
+ const char *parent_name, u8 id,
+ const struct clk_pll_characteristics *characteristics,
+ const struct clk_pll_layout *layout, bool critical)
+{
+ return sam9x60_clk_register_pll(base,
+ UBOOT_DM_CLK_AT91_SAM9X60_FRAC_PLL, name, parent_name, id,
+ characteristics, layout,
+ CLK_GET_RATE_NOCACHE | (critical ? CLK_IS_CRITICAL : 0));
+}
+
+U_BOOT_DRIVER(at91_sam9x60_div_pll_clk) = {
+ .name = UBOOT_DM_CLK_AT91_SAM9X60_DIV_PLL,
+ .id = UCLASS_CLK,
+ .ops = &sam9x60_div_pll_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DRIVER(at91_sam9x60_frac_pll_clk) = {
+ .name = UBOOT_DM_CLK_AT91_SAM9X60_FRAC_PLL,
+ .id = UCLASS_CLK,
+ .ops = &sam9x60_frac_pll_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
diff --git a/drivers/clk/at91/clk-slow.c b/drivers/clk/at91/clk-slow.c
deleted file mode 100644
index 1f8665768b0..00000000000
--- a/drivers/clk/at91/clk-slow.c
+++ /dev/null
@@ -1,36 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2016 Atmel Corporation
- * Wenyou.Yang <wenyou.yang@atmel.com>
- */
-
-#include <common.h>
-#include <clk-uclass.h>
-#include <dm.h>
-
-static int at91_slow_clk_enable(struct clk *clk)
-{
- return 0;
-}
-
-static ulong at91_slow_clk_get_rate(struct clk *clk)
-{
- return CONFIG_SYS_AT91_SLOW_CLOCK;
-}
-
-static struct clk_ops at91_slow_clk_ops = {
- .enable = at91_slow_clk_enable,
- .get_rate = at91_slow_clk_get_rate,
-};
-
-static const struct udevice_id at91_slow_clk_match[] = {
- { .compatible = "atmel,at91sam9x5-clk-slow" },
- {}
-};
-
-U_BOOT_DRIVER(at91_slow_clk) = {
- .name = "at91-slow-clk",
- .id = UCLASS_CLK,
- .of_match = at91_slow_clk_match,
- .ops = &at91_slow_clk_ops,
-};
diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c
index 76b1958670d..82f79e74a19 100644
--- a/drivers/clk/at91/clk-system.c
+++ b/drivers/clk/at91/clk-system.c
@@ -1,111 +1,112 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2016 Atmel Corporation
- * Wenyou.Yang <wenyou.yang@atmel.com>
+ * System clock support for AT91 architectures.
+ *
+ * Copyright (C) Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ *
+ * Based on drivers/clk/at91/clk-system.c from Linux.
*/
-
+#include <asm/processor.h>
#include <common.h>
#include <clk-uclass.h>
#include <dm.h>
-#include <linux/bitops.h>
#include <linux/io.h>
-#include <mach/at91_pmc.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/at91_pmc.h>
+
#include "pmc.h"
-#define SYSTEM_MAX_ID 31
+#define UBOOT_DM_CLK_AT91_SYSTEM "at91-system-clk"
-/**
- * at91_system_clk_bind() - for the system clock driver
- * Recursively bind its children as clk devices.
- *
- * @return: 0 on success, or negative error code on failure
- */
-static int at91_system_clk_bind(struct udevice *dev)
-{
- return at91_clk_sub_device_bind(dev, "system-clk");
-}
-
-static const struct udevice_id at91_system_clk_match[] = {
- { .compatible = "atmel,at91rm9200-clk-system" },
- {}
-};
+#define SYSTEM_MAX_ID 31
-U_BOOT_DRIVER(at91_system_clk) = {
- .name = "at91-system-clk",
- .id = UCLASS_MISC,
- .of_match = at91_system_clk_match,
- .bind = at91_system_clk_bind,
+struct clk_system {
+ void __iomem *base;
+ struct clk clk;
+ u8 id;
};
-/*----------------------------------------------------------*/
+#define to_clk_system(_c) container_of(_c, struct clk_system, clk)
static inline int is_pck(int id)
{
return (id >= 8) && (id <= 15);
}
-static ulong system_clk_get_rate(struct clk *clk)
+static inline bool clk_system_ready(void __iomem *base, int id)
{
- struct clk clk_dev;
- int ret;
+ unsigned int status;
- ret = clk_get_by_index(clk->dev, 0, &clk_dev);
- if (ret)
- return -EINVAL;
+ pmc_read(base, AT91_PMC_SR, &status);
- return clk_get_rate(&clk_dev);
+ return !!(status & (1 << id));
}
-static ulong system_clk_set_rate(struct clk *clk, ulong rate)
+static int clk_system_enable(struct clk *clk)
{
- struct clk clk_dev;
- int ret;
+ struct clk_system *sys = to_clk_system(clk);
- ret = clk_get_by_index(clk->dev, 0, &clk_dev);
- if (ret)
- return -EINVAL;
+ pmc_write(sys->base, AT91_PMC_SCER, 1 << sys->id);
- return clk_set_rate(&clk_dev, rate);
+ if (!is_pck(sys->id))
+ return 0;
+
+ while (!clk_system_ready(sys->base, sys->id)) {
+ debug("waiting for pck%u\n", sys->id);
+ cpu_relax();
+ }
+
+ return 0;
}
-static int system_clk_enable(struct clk *clk)
+static int clk_system_disable(struct clk *clk)
{
- struct pmc_platdata *plat = dev_get_platdata(clk->dev);
- struct at91_pmc *pmc = plat->reg_base;
- u32 mask;
+ struct clk_system *sys = to_clk_system(clk);
- if (clk->id > SYSTEM_MAX_ID)
- return -EINVAL;
+ pmc_write(sys->base, AT91_PMC_SCDR, 1 << sys->id);
- mask = BIT(clk->id);
+ return 0;
+}
- writel(mask, &pmc->scer);
+static const struct clk_ops system_ops = {
+ .enable = clk_system_enable,
+ .disable = clk_system_disable,
+ .get_rate = clk_generic_get_rate,
+};
- /**
- * For the programmable clocks the Ready status in the PMC
- * status register should be checked after enabling.
- * For other clocks this is unnecessary.
- */
- if (!is_pck(clk->id))
- return 0;
+struct clk *at91_clk_register_system(void __iomem *base, const char *name,
+ const char *parent_name, u8 id)
+{
+ struct clk_system *sys;
+ struct clk *clk;
+ int ret;
- while (!(readl(&pmc->sr) & mask))
- ;
+ if (!base || !name || !parent_name || id > SYSTEM_MAX_ID)
+ return ERR_PTR(-EINVAL);
- return 0;
-}
+ sys = kzalloc(sizeof(*sys), GFP_KERNEL);
+ if (!sys)
+ return ERR_PTR(-ENOMEM);
-static struct clk_ops system_clk_ops = {
- .of_xlate = at91_clk_of_xlate,
- .get_rate = system_clk_get_rate,
- .set_rate = system_clk_set_rate,
- .enable = system_clk_enable,
-};
+ sys->id = id;
+ sys->base = base;
-U_BOOT_DRIVER(system_clk) = {
- .name = "system-clk",
+ clk = &sys->clk;
+ clk->flags = CLK_GET_RATE_NOCACHE;
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_SYSTEM, name, parent_name);
+ if (ret) {
+ kfree(sys);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(at91_system_clk) = {
+ .name = UBOOT_DM_CLK_AT91_SYSTEM,
.id = UCLASS_CLK,
- .probe = at91_clk_probe,
- .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
- .ops = &system_clk_ops,
+ .ops = &system_ops,
+ .flags = DM_FLAG_PRE_RELOC,
};
diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c
deleted file mode 100644
index af9d7243693..00000000000
--- a/drivers/clk/at91/clk-usb.c
+++ /dev/null
@@ -1,147 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2018 Microhip / Atmel Corporation
- * Wenyou.Yang <wenyou.yang@microchip.com>
- */
-
-#include <common.h>
-#include <clk-uclass.h>
-#include <log.h>
-#include <dm/device.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <mach/at91_pmc.h>
-#include "pmc.h"
-
-DECLARE_GLOBAL_DATA_PTR;
-
-#define AT91_USB_CLK_SOURCE_MAX 2
-#define AT91_USB_CLK_MAX_DIV 15
-
-struct at91_usb_clk_priv {
- u32 num_clksource;
-};
-
-static ulong at91_usb_clk_get_rate(struct clk *clk)
-{
- struct pmc_platdata *plat = dev_get_platdata(clk->dev);
- struct at91_pmc *pmc = plat->reg_base;
- struct clk source;
- u32 tmp, usbdiv;
- u8 source_index;
- int ret;
-
- tmp = readl(&pmc->pcr);
- source_index = (tmp >> AT91_PMC_USB_USBS_OFFSET) &
- AT91_PMC_USB_USBS_MASK;
- usbdiv = (tmp >> AT91_PMC_USB_DIV_OFFSET) & AT91_PMC_USB_DIV_MASK;
-
- ret = clk_get_by_index(clk->dev, source_index, &source);
- if (ret)
- return 0;
-
- return clk_get_rate(&source) / (usbdiv + 1);
-}
-
-static ulong at91_usb_clk_set_rate(struct clk *clk, ulong rate)
-{
- struct pmc_platdata *plat = dev_get_platdata(clk->dev);
- struct at91_pmc *pmc = plat->reg_base;
- struct at91_usb_clk_priv *priv = dev_get_priv(clk->dev);
- struct clk source, best_source;
- ulong tmp_rate, best_rate = rate, source_rate;
- int tmp_diff, best_diff = -1;
- u32 div, best_div = 0;
- u8 best_source_index = 0;
- u8 i;
- u32 tmp;
- int ret;
-
- for (i = 0; i < priv->num_clksource; i++) {
- ret = clk_get_by_index(clk->dev, i, &source);
- if (ret)
- return ret;
-
- source_rate = clk_get_rate(&source);
- if (IS_ERR_VALUE(source_rate))
- return source_rate;
-
- for (div = 1; div < AT91_USB_CLK_MAX_DIV + 2; div++) {
- tmp_rate = DIV_ROUND_CLOSEST(source_rate, div);
- tmp_diff = abs(rate - tmp_rate);
-
- if (best_diff < 0 || best_diff > tmp_diff) {
- best_rate = tmp_rate;
- best_diff = tmp_diff;
-
- best_div = div - 1;
- best_source = source;
- best_source_index = i;
- }
-
- if (!best_diff || tmp_rate < rate)
- break;
- }
-
- if (!best_diff)
- break;
- }
-
- debug("AT91 USB: best sourc: %s, best_rate = %ld, best_div = %d\n",
- best_source.dev->name, best_rate, best_div);
-
- ret = clk_enable(&best_source);
- if (ret)
- return ret;
-
- tmp = AT91_PMC_USB_USBS_(best_source_index) |
- AT91_PMC_USB_DIV_(best_div);
- writel(tmp, &pmc->usb);
-
- return 0;
-}
-
-static struct clk_ops at91_usb_clk_ops = {
- .get_rate = at91_usb_clk_get_rate,
- .set_rate = at91_usb_clk_set_rate,
-};
-
-static int at91_usb_clk_ofdata_to_platdata(struct udevice *dev)
-{
- struct at91_usb_clk_priv *priv = dev_get_priv(dev);
- u32 cells[AT91_USB_CLK_SOURCE_MAX];
- u32 num_clksource;
-
- num_clksource = fdtdec_get_int_array_count(gd->fdt_blob,
- dev_of_offset(dev),
- "clocks", cells,
- AT91_USB_CLK_SOURCE_MAX);
-
- if (!num_clksource)
- return -1;
-
- priv->num_clksource = num_clksource;
-
- return 0;
-}
-
-static int at91_usb_clk_probe(struct udevice *dev)
-{
- return at91_pmc_core_probe(dev);
-}
-
-static const struct udevice_id at91_usb_clk_match[] = {
- { .compatible = "atmel,at91sam9x5-clk-usb" },
- {}
-};
-
-U_BOOT_DRIVER(at91_usb_clk) = {
- .name = "at91-usb-clk",
- .id = UCLASS_CLK,
- .of_match = at91_usb_clk_match,
- .probe = at91_usb_clk_probe,
- .ofdata_to_platdata = at91_usb_clk_ofdata_to_platdata,
- .priv_auto_alloc_size = sizeof(struct at91_usb_clk_priv),
- .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
- .ops = &at91_usb_clk_ops,
-};
diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c
index 18af0bfeaad..7c8bcfb51db 100644
--- a/drivers/clk/at91/clk-utmi.c
+++ b/drivers/clk/at91/clk-utmi.c
@@ -1,49 +1,65 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2016 Atmel Corporation
- * Wenyou.Yang <wenyou.yang@atmel.com>
+ * UTMI clock support for AT91 architectures.
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ *
+ * Based on drivers/clk/at91/clk-utmi.c from Linux.
*/
-
+#include <asm/processor.h>
#include <common.h>
#include <clk-uclass.h>
#include <dm.h>
-#include <syscon.h>
-#include <linux/io.h>
-#include <mach/at91_pmc.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/at91_pmc.h>
#include <mach/at91_sfr.h>
+#include <regmap.h>
+#include <syscon.h>
+
#include "pmc.h"
+#define UBOOT_DM_CLK_AT91_UTMI "at91-utmi-clk"
+#define UBOOT_DM_CLK_AT91_SAMA7G5_UTMI "at91-sama7g5-utmi-clk"
+
/*
* 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 clk_utmi {
+ void __iomem *base;
+ struct regmap *regmap_sfr;
+ struct clk clk;
+};
+
+#define to_clk_utmi(_clk) container_of(_clk, struct clk_utmi, clk)
+
+static inline bool clk_utmi_ready(struct regmap *regmap)
+{
+ unsigned int status;
+
+ pmc_read(regmap, AT91_PMC_SR, &status);
+
+ return !!(status & AT91_PMC_LOCKU);
+}
+
+static int clk_utmi_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;
- int timeout = 2000000;
-
- if (readl(&pmc->sr) & AT91_PMC_LOCKU)
- return 0;
+ struct clk_utmi *utmi = to_clk_utmi(clk);
+ unsigned int uckr = AT91_PMC_UPLLEN | AT91_PMC_UPLLCOUNT |
+ AT91_PMC_BIASEN;
+ unsigned int utmi_ref_clk_freq;
+ ulong parent_rate = clk_get_parent_rate(clk);
/*
* 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) {
+ switch (parent_rate) {
case 12000000:
utmi_ref_clk_freq = 0;
break;
@@ -61,82 +77,158 @@ static int utmi_clk_enable(struct clk *clk)
utmi_ref_clk_freq = 3;
break;
default:
- printf("UTMICK: unsupported mainck rate\n");
+ debug("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;
+ if (utmi->regmap_sfr) {
+ regmap_update_bits(utmi->regmap_sfr, AT91_SFR_UTMICKTRIM,
+ AT91_UTMICKTRIM_FREQ, utmi_ref_clk_freq);
} else if (utmi_ref_clk_freq) {
- printf("UTMICK: sfr node required\n");
+ debug("UTMICK: sfr node required\n");
return -EINVAL;
}
- tmp = readl(&pmc->uckr);
- tmp |= AT91_PMC_UPLLEN |
- AT91_PMC_UPLLCOUNT |
- AT91_PMC_BIASEN;
- writel(tmp, &pmc->uckr);
-
- while ((--timeout) && !(readl(&pmc->sr) & AT91_PMC_LOCKU))
- ;
- if (!timeout) {
- printf("UTMICK: timeout waiting for UPLL lock\n");
- return -ETIMEDOUT;
+ pmc_update_bits(utmi->base, AT91_CKGR_UCKR, uckr, uckr);
+
+ while (!clk_utmi_ready(utmi->base)) {
+ debug("waiting for utmi...\n");
+ cpu_relax();
}
return 0;
}
-static ulong utmi_clk_get_rate(struct clk *clk)
+static int clk_utmi_disable(struct clk *clk)
+{
+ struct clk_utmi *utmi = to_clk_utmi(clk);
+
+ pmc_update_bits(utmi->base, AT91_CKGR_UCKR, AT91_PMC_UPLLEN, 0);
+
+ return 0;
+}
+
+static ulong clk_utmi_get_rate(struct clk *clk)
{
/* UTMI clk rate is fixed. */
return UTMI_RATE;
}
-static struct clk_ops utmi_clk_ops = {
- .enable = utmi_clk_enable,
- .get_rate = utmi_clk_get_rate,
+static const struct clk_ops utmi_ops = {
+ .enable = clk_utmi_enable,
+ .disable = clk_utmi_disable,
+ .get_rate = clk_utmi_get_rate,
};
-static int utmi_clk_ofdata_to_platdata(struct udevice *dev)
+struct clk *at91_clk_register_utmi(void __iomem *base, struct udevice *dev,
+ const char *name, const char *parent_name)
{
- struct pmc_platdata *plat = dev_get_platdata(dev);
struct udevice *syscon;
+ struct clk_utmi *utmi;
+ struct clk *clk;
+ int ret;
+
+ if (!base || !dev || !name || !parent_name)
+ return ERR_PTR(-EINVAL);
+
+ ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
+ "regmap-sfr", &syscon);
+ if (ret)
+ return ERR_PTR(ret);
+
+ utmi = kzalloc(sizeof(*utmi), GFP_KERNEL);
+ if (!utmi)
+ return ERR_PTR(-ENOMEM);
+
+ utmi->base = base;
+ utmi->regmap_sfr = syscon_get_regmap(syscon);
+ if (!utmi->regmap_sfr) {
+ kfree(utmi);
+ return ERR_PTR(-ENODEV);
+ }
- uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
- "regmap-sfr", &syscon);
-
- if (syscon)
- plat->regmap_sfr = syscon_get_regmap(syscon);
+ clk = &utmi->clk;
+ clk->flags = CLK_GET_RATE_NOCACHE;
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_UTMI, name, parent_name);
+ if (ret) {
+ kfree(utmi);
+ clk = ERR_PTR(ret);
+ }
- return 0;
+ return clk;
}
-static int utmi_clk_probe(struct udevice *dev)
+U_BOOT_DRIVER(at91_utmi_clk) = {
+ .name = UBOOT_DM_CLK_AT91_UTMI,
+ .id = UCLASS_CLK,
+ .ops = &utmi_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+static int clk_utmi_sama7g5_enable(struct clk *clk)
{
- return at91_pmc_core_probe(dev);
+ struct clk_utmi *utmi = to_clk_utmi(clk);
+ ulong parent_rate = clk_get_parent_rate(clk);
+ unsigned int val;
+
+ switch (parent_rate) {
+ case 16000000:
+ val = 0;
+ break;
+ case 20000000:
+ val = 2;
+ break;
+ case 24000000:
+ val = 3;
+ break;
+ case 32000000:
+ val = 5;
+ break;
+ default:
+ debug("UTMICK: unsupported main_xtal rate\n");
+ return -EINVAL;
+ }
+
+ pmc_write(utmi->base, AT91_PMC_XTALF, val);
+
+ return 0;
}
-static const struct udevice_id utmi_clk_match[] = {
- { .compatible = "atmel,at91sam9x5-clk-utmi" },
- {}
+static const struct clk_ops sama7g5_utmi_ops = {
+ .enable = clk_utmi_sama7g5_enable,
+ .get_rate = clk_utmi_get_rate,
};
-U_BOOT_DRIVER(at91sam9x5_utmi_clk) = {
- .name = "at91sam9x5-utmi-clk",
+struct clk *at91_clk_sama7g5_register_utmi(void __iomem *base,
+ const char *name, const char *parent_name)
+{
+ struct clk_utmi *utmi;
+ struct clk *clk;
+ int ret;
+
+ if (!base || !name || !parent_name)
+ return ERR_PTR(-EINVAL);
+
+ utmi = kzalloc(sizeof(*utmi), GFP_KERNEL);
+ if (!utmi)
+ return ERR_PTR(-ENOMEM);
+
+ utmi->base = base;
+
+ clk = &utmi->clk;
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAMA7G5_UTMI, name,
+ parent_name);
+ if (ret) {
+ kfree(utmi);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
+U_BOOT_DRIVER(at91_sama7g5_utmi_clk) = {
+ .name = UBOOT_DM_CLK_AT91_SAMA7G5_UTMI,
.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,
+ .ops = &sama7g5_utmi_ops,
+ .flags = DM_FLAG_PRE_RELOC,
};
diff --git a/drivers/clk/at91/compat.c b/drivers/clk/at91/compat.c
new file mode 100644
index 00000000000..8cf6254046d
--- /dev/null
+++ b/drivers/clk/at91/compat.c
@@ -0,0 +1,1023 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Compatible code for non CCF AT91 platforms.
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ */
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <dm/lists.h>
+#include <dm/util.h>
+#include <mach/at91_pmc.h>
+#include <mach/at91_sfr.h>
+#include <regmap.h>
+#include <syscon.h>
+
+#include "pmc.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct pmc_platdata {
+ struct at91_pmc *reg_base;
+ struct regmap *regmap_sfr;
+};
+
+static const struct udevice_id at91_pmc_match[] = {
+ { .compatible = "atmel,at91rm9200-pmc" },
+ { .compatible = "atmel,at91sam9260-pmc" },
+ { .compatible = "atmel,at91sam9g45-pmc" },
+ { .compatible = "atmel,at91sam9n12-pmc" },
+ { .compatible = "atmel,at91sam9x5-pmc" },
+ { .compatible = "atmel,sama5d3-pmc" },
+ { .compatible = "atmel,sama5d2-pmc" },
+ {}
+};
+
+U_BOOT_DRIVER(at91_pmc) = {
+ .name = "at91-pmc",
+ .id = UCLASS_SIMPLE_BUS,
+ .of_match = at91_pmc_match,
+};
+
+static int at91_pmc_core_probe(struct udevice *dev)
+{
+ struct pmc_platdata *plat = dev_get_platdata(dev);
+
+ dev = dev_get_parent(dev);
+
+ plat->reg_base = dev_read_addr_ptr(dev);
+
+ return 0;
+}
+
+/**
+ * at91_clk_sub_device_bind() - for the at91 clock driver
+ * Recursively bind its children as clk devices.
+ *
+ * @return: 0 on success, or negative error code on failure
+ */
+int at91_clk_sub_device_bind(struct udevice *dev, const char *drv_name)
+{
+ const void *fdt = gd->fdt_blob;
+ int offset = dev_of_offset(dev);
+ bool pre_reloc_only = !(gd->flags & GD_FLG_RELOC);
+ const char *name;
+ int ret;
+
+ for (offset = fdt_first_subnode(fdt, offset);
+ offset > 0;
+ offset = fdt_next_subnode(fdt, offset)) {
+ if (pre_reloc_only &&
+ !ofnode_pre_reloc(offset_to_ofnode(offset)))
+ continue;
+ /*
+ * If this node has "compatible" property, this is not
+ * a clock sub-node, but a normal device. skip.
+ */
+ fdt_get_property(fdt, offset, "compatible", &ret);
+ if (ret >= 0)
+ continue;
+
+ if (ret != -FDT_ERR_NOTFOUND)
+ return ret;
+
+ name = fdt_get_name(fdt, offset, NULL);
+ if (!name)
+ return -EINVAL;
+ ret = device_bind_driver_to_node(dev, drv_name, name,
+ offset_to_ofnode(offset), NULL);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int at91_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args)
+{
+ int periph;
+
+ if (args->args_count) {
+ debug("Invalid args_count: %d\n", args->args_count);
+ return -EINVAL;
+ }
+
+ periph = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(clk->dev), "reg",
+ -1);
+ if (periph < 0)
+ return -EINVAL;
+
+ clk->id = periph;
+
+ return 0;
+}
+
+int at91_clk_probe(struct udevice *dev)
+{
+ struct udevice *dev_periph_container, *dev_pmc;
+ struct pmc_platdata *plat = dev_get_platdata(dev);
+
+ dev_periph_container = dev_get_parent(dev);
+ dev_pmc = dev_get_parent(dev_periph_container);
+
+ plat->reg_base = dev_read_addr_ptr(dev_pmc);
+
+ return 0;
+}
+
+/* SCKC specific code. */
+static const struct udevice_id at91_sckc_match[] = {
+ { .compatible = "atmel,at91sam9x5-sckc" },
+ {}
+};
+
+U_BOOT_DRIVER(at91_sckc) = {
+ .name = "at91-sckc",
+ .id = UCLASS_SIMPLE_BUS,
+ .of_match = at91_sckc_match,
+};
+
+/* Slow clock specific code. */
+static int at91_slow_clk_enable(struct clk *clk)
+{
+ return 0;
+}
+
+static ulong at91_slow_clk_get_rate(struct clk *clk)
+{
+ return CONFIG_SYS_AT91_SLOW_CLOCK;
+}
+
+static struct clk_ops at91_slow_clk_ops = {
+ .enable = at91_slow_clk_enable,
+ .get_rate = at91_slow_clk_get_rate,
+};
+
+static const struct udevice_id at91_slow_clk_match[] = {
+ { .compatible = "atmel,at91sam9x5-clk-slow" },
+ {}
+};
+
+U_BOOT_DRIVER(at91_slow_clk) = {
+ .name = "at91-slow-clk",
+ .id = UCLASS_CLK,
+ .of_match = at91_slow_clk_match,
+ .ops = &at91_slow_clk_ops,
+};
+
+/* Master clock specific code. */
+static ulong at91_master_clk_get_rate(struct clk *clk)
+{
+ return gd->arch.mck_rate_hz;
+}
+
+static struct clk_ops at91_master_clk_ops = {
+ .get_rate = at91_master_clk_get_rate,
+};
+
+static const struct udevice_id at91_master_clk_match[] = {
+ { .compatible = "atmel,at91rm9200-clk-master" },
+ { .compatible = "atmel,at91sam9x5-clk-master" },
+ {}
+};
+
+U_BOOT_DRIVER(at91_master_clk) = {
+ .name = "at91-master-clk",
+ .id = UCLASS_CLK,
+ .of_match = at91_master_clk_match,
+ .ops = &at91_master_clk_ops,
+};
+
+/* Main osc clock specific code. */
+static int main_osc_clk_enable(struct clk *clk)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+
+ if (readl(&pmc->sr) & AT91_PMC_MOSCSELS)
+ return 0;
+
+ return -EINVAL;
+}
+
+static ulong main_osc_clk_get_rate(struct clk *clk)
+{
+ return gd->arch.main_clk_rate_hz;
+}
+
+static struct clk_ops main_osc_clk_ops = {
+ .enable = main_osc_clk_enable,
+ .get_rate = main_osc_clk_get_rate,
+};
+
+static int main_osc_clk_probe(struct udevice *dev)
+{
+ return at91_pmc_core_probe(dev);
+}
+
+static const struct udevice_id main_osc_clk_match[] = {
+ { .compatible = "atmel,at91sam9x5-clk-main" },
+ {}
+};
+
+U_BOOT_DRIVER(at91sam9x5_main_osc_clk) = {
+ .name = "at91sam9x5-main-osc-clk",
+ .id = UCLASS_CLK,
+ .of_match = main_osc_clk_match,
+ .probe = main_osc_clk_probe,
+ .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
+ .ops = &main_osc_clk_ops,
+};
+
+/* PLLA clock specific code. */
+static int plla_clk_enable(struct clk *clk)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+
+ if (readl(&pmc->sr) & AT91_PMC_LOCKA)
+ return 0;
+
+ return -EINVAL;
+}
+
+static ulong plla_clk_get_rate(struct clk *clk)
+{
+ return gd->arch.plla_rate_hz;
+}
+
+static struct clk_ops plla_clk_ops = {
+ .enable = plla_clk_enable,
+ .get_rate = plla_clk_get_rate,
+};
+
+static int plla_clk_probe(struct udevice *dev)
+{
+ return at91_pmc_core_probe(dev);
+}
+
+static const struct udevice_id plla_clk_match[] = {
+ { .compatible = "atmel,sama5d3-clk-pll" },
+ {}
+};
+
+U_BOOT_DRIVER(at91_plla_clk) = {
+ .name = "at91-plla-clk",
+ .id = UCLASS_CLK,
+ .of_match = plla_clk_match,
+ .probe = plla_clk_probe,
+ .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
+ .ops = &plla_clk_ops,
+};
+
+/* PLLA DIV clock specific code. */
+static int at91_plladiv_clk_enable(struct clk *clk)
+{
+ return 0;
+}
+
+static ulong at91_plladiv_clk_get_rate(struct clk *clk)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+ struct clk source;
+ ulong clk_rate;
+ int ret;
+
+ ret = clk_get_by_index(clk->dev, 0, &source);
+ if (ret)
+ return -EINVAL;
+
+ clk_rate = clk_get_rate(&source);
+ if (readl(&pmc->mckr) & AT91_PMC_MCKR_PLLADIV_2)
+ clk_rate /= 2;
+
+ return clk_rate;
+}
+
+static ulong at91_plladiv_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+ struct clk source;
+ ulong parent_rate;
+ int ret;
+
+ ret = clk_get_by_index(clk->dev, 0, &source);
+ if (ret)
+ return -EINVAL;
+
+ parent_rate = clk_get_rate(&source);
+ if ((parent_rate != rate) && ((parent_rate) / 2 != rate))
+ return -EINVAL;
+
+ if (parent_rate != rate) {
+ writel((readl(&pmc->mckr) | AT91_PMC_MCKR_PLLADIV_2),
+ &pmc->mckr);
+ }
+
+ return 0;
+}
+
+static struct clk_ops at91_plladiv_clk_ops = {
+ .enable = at91_plladiv_clk_enable,
+ .get_rate = at91_plladiv_clk_get_rate,
+ .set_rate = at91_plladiv_clk_set_rate,
+};
+
+static int at91_plladiv_clk_probe(struct udevice *dev)
+{
+ return at91_pmc_core_probe(dev);
+}
+
+static const struct udevice_id at91_plladiv_clk_match[] = {
+ { .compatible = "atmel,at91sam9x5-clk-plldiv" },
+ {}
+};
+
+U_BOOT_DRIVER(at91_plladiv_clk) = {
+ .name = "at91-plladiv-clk",
+ .id = UCLASS_CLK,
+ .of_match = at91_plladiv_clk_match,
+ .probe = at91_plladiv_clk_probe,
+ .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
+ .ops = &at91_plladiv_clk_ops,
+};
+
+/* System clock specific code. */
+#define SYSTEM_MAX_ID 31
+
+/**
+ * at91_system_clk_bind() - for the system clock driver
+ * Recursively bind its children as clk devices.
+ *
+ * @return: 0 on success, or negative error code on failure
+ */
+static int at91_system_clk_bind(struct udevice *dev)
+{
+ return at91_clk_sub_device_bind(dev, "system-clk");
+}
+
+static const struct udevice_id at91_system_clk_match[] = {
+ { .compatible = "atmel,at91rm9200-clk-system" },
+ {}
+};
+
+U_BOOT_DRIVER(at91_system_clk) = {
+ .name = "at91-system-clk",
+ .id = UCLASS_MISC,
+ .of_match = at91_system_clk_match,
+ .bind = at91_system_clk_bind,
+};
+
+static inline int is_pck(int id)
+{
+ return (id >= 8) && (id <= 15);
+}
+
+static ulong system_clk_get_rate(struct clk *clk)
+{
+ struct clk clk_dev;
+ int ret;
+
+ ret = clk_get_by_index(clk->dev, 0, &clk_dev);
+ if (ret)
+ return -EINVAL;
+
+ return clk_get_rate(&clk_dev);
+}
+
+static ulong system_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct clk clk_dev;
+ int ret;
+
+ ret = clk_get_by_index(clk->dev, 0, &clk_dev);
+ if (ret)
+ return -EINVAL;
+
+ return clk_set_rate(&clk_dev, rate);
+}
+
+static int system_clk_enable(struct clk *clk)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+ u32 mask;
+
+ if (clk->id > SYSTEM_MAX_ID)
+ return -EINVAL;
+
+ mask = BIT(clk->id);
+
+ writel(mask, &pmc->scer);
+
+ /**
+ * For the programmable clocks the Ready status in the PMC
+ * status register should be checked after enabling.
+ * For other clocks this is unnecessary.
+ */
+ if (!is_pck(clk->id))
+ return 0;
+
+ while (!(readl(&pmc->sr) & mask))
+ ;
+
+ return 0;
+}
+
+static struct clk_ops system_clk_ops = {
+ .of_xlate = at91_clk_of_xlate,
+ .get_rate = system_clk_get_rate,
+ .set_rate = system_clk_set_rate,
+ .enable = system_clk_enable,
+};
+
+U_BOOT_DRIVER(system_clk) = {
+ .name = "system-clk",
+ .id = UCLASS_CLK,
+ .probe = at91_clk_probe,
+ .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
+ .ops = &system_clk_ops,
+};
+
+/* Peripheral clock specific code. */
+#define PERIPHERAL_ID_MIN 2
+#define PERIPHERAL_ID_MAX 31
+#define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX))
+
+enum periph_clk_type {
+ CLK_PERIPH_AT91RM9200 = 0,
+ CLK_PERIPH_AT91SAM9X5,
+};
+
+/**
+ * sam9x5_periph_clk_bind() - for the periph clock driver
+ * Recursively bind its children as clk devices.
+ *
+ * @return: 0 on success, or negative error code on failure
+ */
+static int sam9x5_periph_clk_bind(struct udevice *dev)
+{
+ return at91_clk_sub_device_bind(dev, "periph-clk");
+}
+
+static const struct udevice_id sam9x5_periph_clk_match[] = {
+ {
+ .compatible = "atmel,at91rm9200-clk-peripheral",
+ .data = CLK_PERIPH_AT91RM9200,
+ },
+ {
+ .compatible = "atmel,at91sam9x5-clk-peripheral",
+ .data = CLK_PERIPH_AT91SAM9X5,
+ },
+ {}
+};
+
+U_BOOT_DRIVER(sam9x5_periph_clk) = {
+ .name = "sam9x5-periph-clk",
+ .id = UCLASS_MISC,
+ .of_match = sam9x5_periph_clk_match,
+ .bind = sam9x5_periph_clk_bind,
+};
+
+static int periph_clk_enable(struct clk *clk)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+ enum periph_clk_type clk_type;
+ void *addr;
+
+ if (clk->id < PERIPHERAL_ID_MIN)
+ return -1;
+
+ clk_type = dev_get_driver_data(dev_get_parent(clk->dev));
+ if (clk_type == CLK_PERIPH_AT91RM9200) {
+ addr = &pmc->pcer;
+ if (clk->id > PERIPHERAL_ID_MAX)
+ addr = &pmc->pcer1;
+
+ setbits_le32(addr, PERIPHERAL_MASK(clk->id));
+ } else {
+ writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr);
+ setbits_le32(&pmc->pcr,
+ AT91_PMC_PCR_CMD_WRITE | AT91_PMC_PCR_EN);
+ }
+
+ return 0;
+}
+
+static ulong periph_get_rate(struct clk *clk)
+{
+ struct udevice *dev;
+ struct clk clk_dev;
+ ulong clk_rate;
+ int ret;
+
+ dev = dev_get_parent(clk->dev);
+
+ ret = clk_get_by_index(dev, 0, &clk_dev);
+ if (ret)
+ return ret;
+
+ clk_rate = clk_get_rate(&clk_dev);
+
+ clk_free(&clk_dev);
+
+ return clk_rate;
+}
+
+static struct clk_ops periph_clk_ops = {
+ .of_xlate = at91_clk_of_xlate,
+ .enable = periph_clk_enable,
+ .get_rate = periph_get_rate,
+};
+
+U_BOOT_DRIVER(clk_periph) = {
+ .name = "periph-clk",
+ .id = UCLASS_CLK,
+ .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
+ .probe = at91_clk_probe,
+ .ops = &periph_clk_ops,
+};
+
+/* UTMI clock specific code. */
+#ifdef CONFIG_AT91_UTMI
+
+/*
+ * 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;
+ int timeout = 2000000;
+
+ 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 |
+ AT91_PMC_BIASEN;
+ writel(tmp, &pmc->uckr);
+
+ while ((--timeout) && !(readl(&pmc->sr) & AT91_PMC_LOCKU))
+ ;
+ if (!timeout) {
+ printf("UTMICK: timeout waiting for UPLL lock\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static ulong utmi_clk_get_rate(struct clk *clk)
+{
+ /* UTMI clk rate is fixed. */
+ return UTMI_RATE;
+}
+
+static struct clk_ops utmi_clk_ops = {
+ .enable = utmi_clk_enable,
+ .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);
+}
+
+static const struct udevice_id utmi_clk_match[] = {
+ { .compatible = "atmel,at91sam9x5-clk-utmi" },
+ {}
+};
+
+U_BOOT_DRIVER(at91sam9x5_utmi_clk) = {
+ .name = "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,
+};
+
+#endif /* CONFIG_AT91_UTMI */
+
+/* H32MX clock specific code. */
+#ifdef CONFIG_AT91_H32MX
+
+#define H32MX_MAX_FREQ 90000000
+
+static ulong sama5d4_h32mx_clk_get_rate(struct clk *clk)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+ ulong rate = gd->arch.mck_rate_hz;
+
+ if (readl(&pmc->mckr) & AT91_PMC_MCKR_H32MXDIV)
+ rate /= 2;
+
+ if (rate > H32MX_MAX_FREQ)
+ dev_dbg(clk->dev, "H32MX clock is too fast\n");
+
+ return rate;
+}
+
+static struct clk_ops sama5d4_h32mx_clk_ops = {
+ .get_rate = sama5d4_h32mx_clk_get_rate,
+};
+
+static int sama5d4_h32mx_clk_probe(struct udevice *dev)
+{
+ return at91_pmc_core_probe(dev);
+}
+
+static const struct udevice_id sama5d4_h32mx_clk_match[] = {
+ { .compatible = "atmel,sama5d4-clk-h32mx" },
+ {}
+};
+
+U_BOOT_DRIVER(sama5d4_h32mx_clk) = {
+ .name = "sama5d4-h32mx-clk",
+ .id = UCLASS_CLK,
+ .of_match = sama5d4_h32mx_clk_match,
+ .probe = sama5d4_h32mx_clk_probe,
+ .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
+ .ops = &sama5d4_h32mx_clk_ops,
+};
+
+#endif /* CONFIG_AT91_H32MX */
+
+/* Generic clock specific code. */
+#ifdef CONFIG_AT91_GENERIC_CLK
+
+#define GENERATED_SOURCE_MAX 6
+#define GENERATED_MAX_DIV 255
+
+/**
+ * generated_clk_bind() - for the generated clock driver
+ * Recursively bind its children as clk devices.
+ *
+ * @return: 0 on success, or negative error code on failure
+ */
+static int generated_clk_bind(struct udevice *dev)
+{
+ return at91_clk_sub_device_bind(dev, "generic-clk");
+}
+
+static const struct udevice_id generated_clk_match[] = {
+ { .compatible = "atmel,sama5d2-clk-generated" },
+ {}
+};
+
+U_BOOT_DRIVER(generated_clk) = {
+ .name = "generated-clk",
+ .id = UCLASS_MISC,
+ .of_match = generated_clk_match,
+ .bind = generated_clk_bind,
+};
+
+struct generic_clk_priv {
+ u32 num_parents;
+};
+
+static ulong generic_clk_get_rate(struct clk *clk)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+ struct clk parent;
+ ulong clk_rate;
+ u32 tmp, gckdiv;
+ u8 clock_source, parent_index;
+ int ret;
+
+ writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr);
+ tmp = readl(&pmc->pcr);
+ clock_source = (tmp >> AT91_PMC_PCR_GCKCSS_OFFSET) &
+ AT91_PMC_PCR_GCKCSS_MASK;
+ gckdiv = (tmp >> AT91_PMC_PCR_GCKDIV_OFFSET) & AT91_PMC_PCR_GCKDIV_MASK;
+
+ parent_index = clock_source - 1;
+ ret = clk_get_by_index(dev_get_parent(clk->dev), parent_index, &parent);
+ if (ret)
+ return 0;
+
+ clk_rate = clk_get_rate(&parent) / (gckdiv + 1);
+
+ clk_free(&parent);
+
+ return clk_rate;
+}
+
+static ulong generic_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+ struct generic_clk_priv *priv = dev_get_priv(clk->dev);
+ struct clk parent, best_parent;
+ ulong tmp_rate, best_rate = rate, parent_rate;
+ int tmp_diff, best_diff = -1;
+ u32 div, best_div = 0;
+ u8 best_parent_index, best_clock_source = 0;
+ u8 i;
+ u32 tmp;
+ int ret;
+
+ for (i = 0; i < priv->num_parents; i++) {
+ ret = clk_get_by_index(dev_get_parent(clk->dev), i, &parent);
+ if (ret)
+ return ret;
+
+ parent_rate = clk_get_rate(&parent);
+ if (IS_ERR_VALUE(parent_rate))
+ return parent_rate;
+
+ for (div = 1; div < GENERATED_MAX_DIV + 2; div++) {
+ tmp_rate = DIV_ROUND_CLOSEST(parent_rate, div);
+ tmp_diff = abs(rate - tmp_rate);
+
+ if (best_diff < 0 || best_diff > tmp_diff) {
+ best_rate = tmp_rate;
+ best_diff = tmp_diff;
+
+ best_div = div - 1;
+ best_parent = parent;
+ best_parent_index = i;
+ best_clock_source = best_parent_index + 1;
+ }
+
+ if (!best_diff || tmp_rate < rate)
+ break;
+ }
+
+ if (!best_diff)
+ break;
+ }
+
+ debug("GCK: best parent: %s, best_rate = %ld, best_div = %d\n",
+ best_parent.dev->name, best_rate, best_div);
+
+ ret = clk_enable(&best_parent);
+ if (ret)
+ return ret;
+
+ writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr);
+ tmp = readl(&pmc->pcr);
+ tmp &= ~(AT91_PMC_PCR_GCKDIV | AT91_PMC_PCR_GCKCSS);
+ tmp |= AT91_PMC_PCR_GCKCSS_(best_clock_source) |
+ AT91_PMC_PCR_CMD_WRITE |
+ AT91_PMC_PCR_GCKDIV_(best_div) |
+ AT91_PMC_PCR_GCKEN;
+ writel(tmp, &pmc->pcr);
+
+ while (!(readl(&pmc->sr) & AT91_PMC_GCKRDY))
+ ;
+
+ return 0;
+}
+
+static struct clk_ops generic_clk_ops = {
+ .of_xlate = at91_clk_of_xlate,
+ .get_rate = generic_clk_get_rate,
+ .set_rate = generic_clk_set_rate,
+};
+
+static int generic_clk_ofdata_to_platdata(struct udevice *dev)
+{
+ struct generic_clk_priv *priv = dev_get_priv(dev);
+ u32 cells[GENERATED_SOURCE_MAX];
+ u32 num_parents;
+
+ num_parents = fdtdec_get_int_array_count(gd->fdt_blob,
+ dev_of_offset(dev_get_parent(dev)), "clocks", cells,
+ GENERATED_SOURCE_MAX);
+
+ if (!num_parents)
+ return -1;
+
+ priv->num_parents = num_parents;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(generic_clk) = {
+ .name = "generic-clk",
+ .id = UCLASS_CLK,
+ .probe = at91_clk_probe,
+ .ofdata_to_platdata = generic_clk_ofdata_to_platdata,
+ .priv_auto_alloc_size = sizeof(struct generic_clk_priv),
+ .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
+ .ops = &generic_clk_ops,
+};
+
+#endif /* CONFIG_AT91_GENERIC_CLK */
+
+/* USB clock specific code. */
+#ifdef CONFIG_AT91_USB_CLK
+
+#define AT91_USB_CLK_SOURCE_MAX 2
+#define AT91_USB_CLK_MAX_DIV 15
+
+struct at91_usb_clk_priv {
+ u32 num_clksource;
+};
+
+static ulong at91_usb_clk_get_rate(struct clk *clk)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+ struct clk source;
+ u32 tmp, usbdiv;
+ u8 source_index;
+ int ret;
+
+ tmp = readl(&pmc->pcr);
+ source_index = (tmp >> AT91_PMC_USB_USBS_OFFSET) &
+ AT91_PMC_USB_USBS_MASK;
+ usbdiv = (tmp >> AT91_PMC_USB_DIV_OFFSET) & AT91_PMC_USB_DIV_MASK;
+
+ ret = clk_get_by_index(clk->dev, source_index, &source);
+ if (ret)
+ return 0;
+
+ return clk_get_rate(&source) / (usbdiv + 1);
+}
+
+static ulong at91_usb_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct pmc_platdata *plat = dev_get_platdata(clk->dev);
+ struct at91_pmc *pmc = plat->reg_base;
+ struct at91_usb_clk_priv *priv = dev_get_priv(clk->dev);
+ struct clk source, best_source;
+ ulong tmp_rate, best_rate = rate, source_rate;
+ int tmp_diff, best_diff = -1;
+ u32 div, best_div = 0;
+ u8 best_source_index = 0;
+ u8 i;
+ u32 tmp;
+ int ret;
+
+ for (i = 0; i < priv->num_clksource; i++) {
+ ret = clk_get_by_index(clk->dev, i, &source);
+ if (ret)
+ return ret;
+
+ source_rate = clk_get_rate(&source);
+ if (IS_ERR_VALUE(source_rate))
+ return source_rate;
+
+ for (div = 1; div < AT91_USB_CLK_MAX_DIV + 2; div++) {
+ tmp_rate = DIV_ROUND_CLOSEST(source_rate, div);
+ tmp_diff = abs(rate - tmp_rate);
+
+ if (best_diff < 0 || best_diff > tmp_diff) {
+ best_rate = tmp_rate;
+ best_diff = tmp_diff;
+
+ best_div = div - 1;
+ best_source = source;
+ best_source_index = i;
+ }
+
+ if (!best_diff || tmp_rate < rate)
+ break;
+ }
+
+ if (!best_diff)
+ break;
+ }
+
+ debug("AT91 USB: best sourc: %s, best_rate = %ld, best_div = %d\n",
+ best_source.dev->name, best_rate, best_div);
+
+ ret = clk_enable(&best_source);
+ if (ret)
+ return ret;
+
+ tmp = AT91_PMC_USB_USBS_(best_source_index) |
+ AT91_PMC_USB_DIV_(best_div);
+ writel(tmp, &pmc->usb);
+
+ return 0;
+}
+
+static struct clk_ops at91_usb_clk_ops = {
+ .get_rate = at91_usb_clk_get_rate,
+ .set_rate = at91_usb_clk_set_rate,
+};
+
+static int at91_usb_clk_ofdata_to_platdata(struct udevice *dev)
+{
+ struct at91_usb_clk_priv *priv = dev_get_priv(dev);
+ u32 cells[AT91_USB_CLK_SOURCE_MAX];
+ u32 num_clksource;
+
+ num_clksource = fdtdec_get_int_array_count(gd->fdt_blob,
+ dev_of_offset(dev),
+ "clocks", cells,
+ AT91_USB_CLK_SOURCE_MAX);
+
+ if (!num_clksource)
+ return -1;
+
+ priv->num_clksource = num_clksource;
+
+ return 0;
+}
+
+static int at91_usb_clk_probe(struct udevice *dev)
+{
+ return at91_pmc_core_probe(dev);
+}
+
+static const struct udevice_id at91_usb_clk_match[] = {
+ { .compatible = "atmel,at91sam9x5-clk-usb" },
+ {}
+};
+
+U_BOOT_DRIVER(at91_usb_clk) = {
+ .name = "at91-usb-clk",
+ .id = UCLASS_CLK,
+ .of_match = at91_usb_clk_match,
+ .probe = at91_usb_clk_probe,
+ .ofdata_to_platdata = at91_usb_clk_ofdata_to_platdata,
+ .priv_auto_alloc_size = sizeof(struct at91_usb_clk_priv),
+ .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
+ .ops = &at91_usb_clk_ops,
+};
+
+#endif /* CONFIG_AT91_USB_CLK */
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index ca90abef2d5..660e2319214 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -4,119 +4,167 @@
* Wenyou.Yang <wenyou.yang@atmel.com>
*/
-#include <common.h>
+#include <asm/io.h>
#include <clk-uclass.h>
-#include <dm.h>
-#include <log.h>
-#include <dm/lists.h>
-#include <dm/util.h>
+#include <common.h>
+
#include "pmc.h"
-DECLARE_GLOBAL_DATA_PTR;
-
-static const struct udevice_id at91_pmc_match[] = {
- { .compatible = "atmel,at91rm9200-pmc" },
- { .compatible = "atmel,at91sam9260-pmc" },
- { .compatible = "atmel,at91sam9g45-pmc" },
- { .compatible = "atmel,at91sam9n12-pmc" },
- { .compatible = "atmel,at91sam9x5-pmc" },
- { .compatible = "atmel,sama5d3-pmc" },
- { .compatible = "atmel,sama5d2-pmc" },
- {}
-};
+static int at91_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args)
+{
+ if (args->args_count != 2) {
+ debug("AT91: clk: Invalid args_count: %d\n", args->args_count);
+ return -EINVAL;
+ }
-U_BOOT_DRIVER(atmel_at91rm9200_pmc) = {
- .name = "atmel_at91rm9200_pmc",
- .id = UCLASS_SIMPLE_BUS,
- .of_match = at91_pmc_match,
-};
+ clk->id = AT91_TO_CLK_ID(args->args[0], args->args[1]);
+
+ return 0;
+}
+
+static ulong at91_clk_get_rate(struct clk *clk)
+{
+ struct clk *c;
+ int ret;
+
+ ret = clk_get_by_id(clk->id, &c);
+ if (ret)
+ return ret;
+
+ return clk_get_rate(c);
+}
+
+static ulong at91_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct clk *c;
+ int ret;
-U_BOOT_DRIVER_ALIAS(atmel_at91rm9200_pmc, atmel_at91sam9260_pmc)
+ ret = clk_get_by_id(clk->id, &c);
+ if (ret)
+ return ret;
-/*---------------------------------------------------------*/
+ return clk_set_rate(c, rate);
+}
-int at91_pmc_core_probe(struct udevice *dev)
+static int at91_clk_enable(struct clk *clk)
{
- struct pmc_platdata *plat = dev_get_platdata(dev);
+ struct clk *c;
+ int ret;
- dev = dev_get_parent(dev);
+ ret = clk_get_by_id(clk->id, &c);
+ if (ret)
+ return ret;
- plat->reg_base = dev_read_addr_ptr(dev);
+ return clk_enable(c);
+}
- return 0;
+static int at91_clk_disable(struct clk *clk)
+{
+ struct clk *c;
+ int ret;
+
+ ret = clk_get_by_id(clk->id, &c);
+ if (ret)
+ return ret;
+
+ return clk_disable(c);
}
+const struct clk_ops at91_clk_ops = {
+ .of_xlate = at91_clk_of_xlate,
+ .set_rate = at91_clk_set_rate,
+ .get_rate = at91_clk_get_rate,
+ .enable = at91_clk_enable,
+ .disable = at91_clk_disable,
+};
+
/**
- * at91_clk_sub_device_bind() - for the at91 clock driver
- * Recursively bind its children as clk devices.
+ * pmc_read() - read content at address base + off into val
*
- * @return: 0 on success, or negative error code on failure
+ * @base: base address
+ * @off: offset to read from
+ * @val: where the content of base + off is stored
+ *
+ * @return: void
*/
-int at91_clk_sub_device_bind(struct udevice *dev, const char *drv_name)
+void pmc_read(void __iomem *base, unsigned int off, unsigned int *val)
{
- const void *fdt = gd->fdt_blob;
- int offset = dev_of_offset(dev);
- bool pre_reloc_only = !(gd->flags & GD_FLG_RELOC);
- const char *name;
- int ret;
-
- for (offset = fdt_first_subnode(fdt, offset);
- offset > 0;
- offset = fdt_next_subnode(fdt, offset)) {
- if (pre_reloc_only &&
- !ofnode_pre_reloc(offset_to_ofnode(offset)))
- continue;
- /*
- * If this node has "compatible" property, this is not
- * a clock sub-node, but a normal device. skip.
- */
- fdt_get_property(fdt, offset, "compatible", &ret);
- if (ret >= 0)
- continue;
-
- if (ret != -FDT_ERR_NOTFOUND)
- return ret;
-
- name = fdt_get_name(fdt, offset, NULL);
- if (!name)
- return -EINVAL;
- ret = device_bind_driver_to_node(dev, drv_name, name,
- offset_to_ofnode(offset), NULL);
- if (ret)
- return ret;
- }
+ *val = readl(base + off);
+}
- return 0;
+/**
+ * pmc_write() - write content of val at address base + off
+ *
+ * @base: base address
+ * @off: offset to write to
+ * @val: content to be written at base + off
+ *
+ * @return: void
+ */
+void pmc_write(void __iomem *base, unsigned int off, unsigned int val)
+{
+ writel(val, base + off);
}
-int at91_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args)
+/**
+ * pmc_update_bits() - update a set of bits at address base + off
+ *
+ * @base: base address
+ * @off: offset to be updated
+ * @mask: mask of bits to be updated
+ * @bits: the new value to be updated
+ *
+ * @return: void
+ */
+void pmc_update_bits(void __iomem *base, unsigned int off,
+ unsigned int mask, unsigned int bits)
{
- int periph;
+ unsigned int tmp;
- if (args->args_count) {
- debug("Invalid args_count: %d\n", args->args_count);
- return -EINVAL;
- }
+ tmp = readl(base + off);
+ tmp &= ~mask;
+ writel(tmp | (bits & mask), base + off);
+}
- periph = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(clk->dev), "reg",
- -1);
- if (periph < 0)
+/**
+ * at91_clk_mux_val_to_index() - get parent index in mux table
+ *
+ * @table: clock mux table
+ * @num_parents: clock number of parents
+ * @val: clock id who's mux index should be retrieved
+ *
+ * @return: clock index in mux table or a negative error number in case of
+ * failure
+ */
+int at91_clk_mux_val_to_index(const u32 *table, u32 num_parents, u32 val)
+{
+ int i;
+
+ if (!table || !num_parents)
return -EINVAL;
- clk->id = periph;
+ for (i = 0; i < num_parents; i++) {
+ if (table[i] == val)
+ return i;
+ }
- return 0;
+ return -EINVAL;
}
-int at91_clk_probe(struct udevice *dev)
+/**
+ * at91_clk_mux_index_to_val() - get parent ID corresponding to an entry in
+ * clock's mux table
+ *
+ * @table: clock's mux table
+ * @num_parents: clock's number of parents
+ * @index: index in mux table which clock's ID should be retrieved
+ *
+ * @return: clock ID or a negative error number in case of failure
+ */
+int at91_clk_mux_index_to_val(const u32 *table, u32 num_parents, u32 index)
{
- struct udevice *dev_periph_container, *dev_pmc;
- struct pmc_platdata *plat = dev_get_platdata(dev);
-
- dev_periph_container = dev_get_parent(dev);
- dev_pmc = dev_get_parent(dev_periph_container);
-
- plat->reg_base = dev_read_addr_ptr(dev_pmc);
+ if (!table || !num_parents || index < 0 || index > num_parents)
+ return -EINVAL;
- return 0;
+ return table[index];
}
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
index 517ba1d6b45..a6a714fd220 100644
--- a/drivers/clk/at91/pmc.h
+++ b/drivers/clk/at91/pmc.h
@@ -7,17 +7,141 @@
#ifndef __AT91_PMC_H__
#define __AT91_PMC_H__
-#include <regmap.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
-struct pmc_platdata {
- struct at91_pmc *reg_base;
- struct regmap *regmap_sfr;
+/* Keep a range of 256 available clocks for every clock type. */
+#define AT91_TO_CLK_ID(_t, _i) (((_t) << 8) | ((_i) & 0xff))
+#define AT91_CLK_ID_TO_DID(_i) ((_i) & 0xff)
+
+struct clk_range {
+ unsigned long min;
+ unsigned long max;
+};
+
+struct clk_master_layout {
+ u32 offset;
+ u32 mask;
+ u8 pres_shift;
};
-int at91_pmc_core_probe(struct udevice *dev);
-int at91_clk_sub_device_bind(struct udevice *dev, const char *drv_name);
+extern const struct clk_master_layout at91rm9200_master_layout;
+extern const struct clk_master_layout at91sam9x5_master_layout;
+
+struct clk_master_characteristics {
+ struct clk_range output;
+ u32 divisors[4];
+ u8 have_div3_pres;
+};
+
+struct clk_pll_characteristics {
+ struct clk_range input;
+ int num_output;
+ const struct clk_range *output;
+ u16 *icpll;
+ u8 *out;
+ u8 upll : 1;
+};
+
+struct clk_pll_layout {
+ u32 pllr_mask;
+ u32 mul_mask;
+ u32 frac_mask;
+ u32 div_mask;
+ u32 endiv_mask;
+ u8 mul_shift;
+ u8 frac_shift;
+ u8 div_shift;
+ u8 endiv_shift;
+};
+
+struct clk_programmable_layout {
+ u8 pres_mask;
+ u8 pres_shift;
+ u8 css_mask;
+ u8 have_slck_mck;
+ u8 is_pres_direct;
+};
+
+struct clk_pcr_layout {
+ u32 offset;
+ u32 cmd;
+ u32 div_mask;
+ u32 gckcss_mask;
+ u32 pid_mask;
+};
+
+extern const struct clk_programmable_layout at91rm9200_programmable_layout;
+extern const struct clk_programmable_layout at91sam9g45_programmable_layout;
+extern const struct clk_programmable_layout at91sam9x5_programmable_layout;
+
+extern const struct clk_ops at91_clk_ops;
+
+struct clk *at91_clk_main_rc(void __iomem *reg, const char *name,
+ const char *parent_name);
+struct clk *at91_clk_main_osc(void __iomem *reg, const char *name,
+ const char *parent_name, bool bypass);
+struct clk *at91_clk_rm9200_main(void __iomem *reg, const char *name,
+ const char *parent_name);
+struct clk *at91_clk_sam9x5_main(void __iomem *reg, const char *name,
+ const char * const *parent_names, int num_parents,
+ const u32 *mux_table, int type);
+struct clk *
+sam9x60_clk_register_div_pll(void __iomem *base, const char *name,
+ const char *parent_name, u8 id,
+ const struct clk_pll_characteristics *characteristics,
+ const struct clk_pll_layout *layout, bool critical);
+struct clk *
+sam9x60_clk_register_frac_pll(void __iomem *base, const char *name,
+ const char *parent_name, u8 id,
+ const struct clk_pll_characteristics *characteristics,
+ const struct clk_pll_layout *layout, bool critical);
+struct clk *
+at91_clk_register_master(void __iomem *base, const char *name,
+ const char * const *parent_names, int num_parents,
+ const struct clk_master_layout *layout,
+ const struct clk_master_characteristics *characteristics,
+ const u32 *mux_table);
+struct clk *
+at91_clk_sama7g5_register_master(void __iomem *base, const char *name,
+ const char * const *parent_names, int num_parents,
+ const u32 *mux_table, const u32 *clk_mux_table,
+ bool critical, u8 id);
+struct clk *
+at91_clk_register_utmi(void __iomem *base, struct udevice *dev,
+ const char *name, const char *parent_name);
+struct clk *
+at91_clk_sama7g5_register_utmi(void __iomem *base, const char *name,
+ const char *parent_name);
+struct clk *
+at91_clk_register_programmable(void __iomem *base, const char *name,
+ const char * const *parent_names, u8 num_parents, u8 id,
+ const struct clk_programmable_layout *layout,
+ const u32 *clk_mux_table, const u32 *mux_table);
+struct clk *
+at91_clk_register_system(void __iomem *base, const char *name,
+ const char *parent_name, u8 id);
+struct clk *
+at91_clk_register_peripheral(void __iomem *base, const char *name,
+ const char *parent_name, u32 id);
+struct clk *
+at91_clk_register_sam9x5_peripheral(void __iomem *base,
+ const struct clk_pcr_layout *layout,
+ const char *name, const char *parent_name,
+ u32 id, const struct clk_range *range);
+struct clk *
+at91_clk_register_generic(void __iomem *base,
+ const struct clk_pcr_layout *layout, const char *name,
+ const char * const *parent_names,
+ const u32 *clk_mux_table, const u32 *mux_table,
+ u8 num_parents, u8 id, const struct clk_range *range);
+
+int at91_clk_mux_val_to_index(const u32 *table, u32 num_parents, u32 val);
+int at91_clk_mux_index_to_val(const u32 *table, u32 num_parents, u32 index);
-int at91_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args);
-int at91_clk_probe(struct udevice *dev);
+void pmc_read(void __iomem *base, unsigned int off, unsigned int *val);
+void pmc_write(void __iomem *base, unsigned int off, unsigned int val);
+void pmc_update_bits(void __iomem *base, unsigned int off, unsigned int mask,
+ unsigned int bits);
#endif
diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c
new file mode 100644
index 00000000000..b96937673be
--- /dev/null
+++ b/drivers/clk/at91/sama7g5.c
@@ -0,0 +1,1401 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * SAMA7G5 PMC clock support.
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ *
+ * Based on drivers/clk/at91/sama7g5.c from Linux.
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <dt-bindings/clk/at91.h>
+#include <linux/clk-provider.h>
+
+#include "pmc.h"
+
+/**
+ * Clock identifiers to be used in conjunction with macros like
+ * AT91_TO_CLK_ID()
+ *
+ * @ID_MD_SLCK: TD slow clock identifier
+ * @ID_TD_SLCK: MD slow clock identifier
+ * @ID_MAIN_XTAL: Main Xtal clock identifier
+ * @ID_MAIN_RC: Main RC clock identifier
+ * @ID_MAIN_RC_OSC: Main RC Oscillator clock identifier
+ * @ID_MAIN_OSC: Main Oscillator clock identifier
+ * @ID_MAINCK: MAINCK clock identifier
+ * @ID_PLL_CPU_FRAC: CPU PLL fractional clock identifier
+ * @ID_PLL_CPU_DIV: CPU PLL divider clock identifier
+ * @ID_PLL_SYS_FRAC: SYS PLL fractional clock identifier
+ * @ID_PLL_SYS_DIV: SYS PLL divider clock identifier
+ * @ID_PLL_DDR_FRAC: DDR PLL fractional clock identifier
+ * @ID_PLL_DDR_DIV: DDR PLL divider clock identifier
+ * @ID_PLL_IMG_FRAC: IMC PLL fractional clock identifier
+ * @ID_PLL_IMG_DIV: IMG PLL divider clock identifier
+ * @ID_PLL_BAUD_FRAC: Baud PLL fractional clock identifier
+ * @ID_PLL_BAUD_DIV: Baud PLL divider clock identifier
+ * @ID_PLL_AUDIO_FRAC: Audio PLL fractional clock identifier
+ * @ID_PLL_AUDIO_DIVPMC: Audio PLL PMC divider clock identifier
+ * @ID_PLL_AUDIO_DIVIO: Audio PLL IO divider clock identifier
+ * @ID_PLL_ETH_FRAC: Ethernet PLL fractional clock identifier
+ * @ID_PLL_ETH_DIV: Ethernet PLL divider clock identifier
+
+ * @ID_MCK0: MCK0 clock identifier
+ * @ID_MCK1: MCK1 clock identifier
+ * @ID_MCK2: MCK2 clock identifier
+ * @ID_MCK3: MCK3 clock identifier
+ * @ID_MCK4: MCK4 clock identifier
+
+ * @ID_UTMI: UTMI clock identifier
+
+ * @ID_PROG0: Programmable 0 clock identifier
+ * @ID_PROG1: Programmable 1 clock identifier
+ * @ID_PROG2: Programmable 2 clock identifier
+ * @ID_PROG3: Programmable 3 clock identifier
+ * @ID_PROG4: Programmable 4 clock identifier
+ * @ID_PROG5: Programmable 5 clock identifier
+ * @ID_PROG6: Programmable 6 clock identifier
+ * @ID_PROG7: Programmable 7 clock identifier
+
+ * @ID_PCK0: System clock 0 clock identifier
+ * @ID_PCK1: System clock 1 clock identifier
+ * @ID_PCK2: System clock 2 clock identifier
+ * @ID_PCK3: System clock 3 clock identifier
+ * @ID_PCK4: System clock 4 clock identifier
+ * @ID_PCK5: System clock 5 clock identifier
+ * @ID_PCK6: System clock 6 clock identifier
+ * @ID_PCK7: System clock 7 clock identifier
+ */
+enum pmc_clk_ids {
+ ID_MD_SLCK = 0,
+ ID_TD_SLCK = 1,
+ ID_MAIN_XTAL = 2,
+ ID_MAIN_RC = 3,
+ ID_MAIN_RC_OSC = 4,
+ ID_MAIN_OSC = 5,
+ ID_MAINCK = 6,
+
+ ID_PLL_CPU_FRAC = 7,
+ ID_PLL_CPU_DIV = 8,
+ ID_PLL_SYS_FRAC = 9,
+ ID_PLL_SYS_DIV = 10,
+ ID_PLL_DDR_FRAC = 11,
+ ID_PLL_DDR_DIV = 12,
+ ID_PLL_IMG_FRAC = 13,
+ ID_PLL_IMG_DIV = 14,
+ ID_PLL_BAUD_FRAC = 15,
+ ID_PLL_BAUD_DIV = 16,
+ ID_PLL_AUDIO_FRAC = 17,
+ ID_PLL_AUDIO_DIVPMC = 18,
+ ID_PLL_AUDIO_DIVIO = 19,
+ ID_PLL_ETH_FRAC = 20,
+ ID_PLL_ETH_DIV = 21,
+
+ ID_MCK0 = 22,
+ ID_MCK1 = 23,
+ ID_MCK2 = 24,
+ ID_MCK3 = 25,
+ ID_MCK4 = 26,
+
+ ID_UTMI = 27,
+
+ ID_PROG0 = 28,
+ ID_PROG1 = 29,
+ ID_PROG2 = 30,
+ ID_PROG3 = 31,
+ ID_PROG4 = 32,
+ ID_PROG5 = 33,
+ ID_PROG6 = 34,
+ ID_PROG7 = 35,
+
+ ID_PCK0 = 36,
+ ID_PCK1 = 37,
+ ID_PCK2 = 38,
+ ID_PCK3 = 39,
+ ID_PCK4 = 40,
+ ID_PCK5 = 41,
+ ID_PCK6 = 42,
+ ID_PCK7 = 43,
+
+ ID_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,
+};
+
+/* Clock names used as parents for multiple clocks. */
+static const char *clk_names[] = {
+ [ID_MAIN_RC_OSC] = "main_rc_osc",
+ [ID_MAIN_OSC] = "main_osc",
+ [ID_MAINCK] = "mainck",
+ [ID_PLL_CPU_DIV] = "cpupll_divpmcck",
+ [ID_PLL_SYS_DIV] = "syspll_divpmcck",
+ [ID_PLL_DDR_DIV] = "ddrpll_divpmcck",
+ [ID_PLL_IMG_DIV] = "imgpll_divpmcck",
+ [ID_PLL_BAUD_DIV] = "baudpll_divpmcck",
+ [ID_PLL_AUDIO_DIVPMC] = "audiopll_divpmcck",
+ [ID_PLL_AUDIO_DIVIO] = "audiopll_diviock",
+ [ID_PLL_ETH_DIV] = "ethpll_divpmcck",
+ [ID_MCK0] = "mck0",
+};
+
+/* Fractional PLL output range. */
+static const struct clk_range pll_outputs[] = {
+ { .min = 2343750, .max = 1200000000 },
+};
+
+/* PLL characteristics. */
+static const struct clk_pll_characteristics pll_characteristics = {
+ .input = { .min = 12000000, .max = 50000000 },
+ .num_output = ARRAY_SIZE(pll_outputs),
+ .output = pll_outputs,
+};
+
+/* Layout for fractional PLLs. */
+static const struct clk_pll_layout pll_layout_frac = {
+ .mul_mask = GENMASK(31, 24),
+ .frac_mask = GENMASK(21, 0),
+ .mul_shift = 24,
+ .frac_shift = 0,
+};
+
+/* Layout for DIVPMC dividers. */
+static const struct clk_pll_layout pll_layout_divpmc = {
+ .div_mask = GENMASK(7, 0),
+ .endiv_mask = BIT(29),
+ .div_shift = 0,
+ .endiv_shift = 29,
+};
+
+/* Layout for DIVIO dividers. */
+static const struct clk_pll_layout pll_layout_divio = {
+ .div_mask = GENMASK(19, 12),
+ .endiv_mask = BIT(30),
+ .div_shift = 12,
+ .endiv_shift = 30,
+};
+
+/* MCK0 characteristics. */
+static const struct clk_master_characteristics mck0_characteristics = {
+ .output = { .min = 140000000, .max = 200000000 },
+ .divisors = { 1, 2, 4, 3 },
+ .have_div3_pres = 1,
+};
+
+/* MCK0 layout. */
+static const struct clk_master_layout mck0_layout = {
+ .mask = 0x373,
+ .pres_shift = 4,
+ .offset = 0x28,
+};
+
+/* Programmable clock layout. */
+static const struct clk_programmable_layout programmable_layout = {
+ .pres_mask = 0xff,
+ .pres_shift = 8,
+ .css_mask = 0x1f,
+ .have_slck_mck = 0,
+ .is_pres_direct = 1,
+};
+
+/* Peripheral clock layout. */
+static const struct clk_pcr_layout sama7g5_pcr_layout = {
+ .offset = 0x88,
+ .cmd = BIT(31),
+ .gckcss_mask = GENMASK(12, 8),
+ .pid_mask = GENMASK(6, 0),
+ .div_mask = GENMASK(15, 14),
+};
+
+/**
+ * PLL clocks description
+ * @n: clock name
+ * @p: clock parent
+ * @l: clock layout
+ * @t: clock type
+ * @c: true if clock is critical and cannot be disabled
+ * @id: clock id corresponding to PLL driver
+ * @cid: clock id corresponding to clock subsystem
+ */
+static const struct {
+ const char *n;
+ const char *p;
+ const struct clk_pll_layout *l;
+ u8 t;
+ u8 c;
+ u8 id;
+ u8 cid;
+} sama7g5_plls[] = {
+ {
+ .n = "cpupll_fracck",
+ .p = "mainck",
+ .l = &pll_layout_frac,
+ .t = PLL_TYPE_FRAC,
+ .c = 1,
+ .id = 0,
+ .cid = ID_PLL_CPU_FRAC,
+ },
+
+ {
+ .n = "cpupll_divpmcck",
+ .p = "cpupll_fracck",
+ .l = &pll_layout_divpmc,
+ .t = PLL_TYPE_DIV,
+ .c = 1,
+ .id = 0,
+ .cid = ID_PLL_CPU_DIV,
+ },
+
+ {
+ .n = "syspll_fracck",
+ .p = "mainck",
+ .l = &pll_layout_frac,
+ .t = PLL_TYPE_FRAC,
+ .c = 1,
+ .id = 1,
+ .cid = ID_PLL_SYS_FRAC,
+ },
+
+ {
+ .n = "syspll_divpmcck",
+ .p = "syspll_fracck",
+ .l = &pll_layout_divpmc,
+ .t = PLL_TYPE_DIV,
+ .c = 1,
+ .id = 1,
+ .cid = ID_PLL_SYS_DIV,
+ },
+
+ {
+ .n = "ddrpll_fracck",
+ .p = "mainck",
+ .l = &pll_layout_frac,
+ .t = PLL_TYPE_FRAC,
+ .c = 1,
+ .id = 2,
+ .cid = ID_PLL_DDR_FRAC,
+ },
+
+ {
+ .n = "ddrpll_divpmcck",
+ .p = "ddrpll_fracck",
+ .l = &pll_layout_divpmc,
+ .t = PLL_TYPE_DIV,
+ .c = 1,
+ .id = 2,
+ .cid = ID_PLL_DDR_DIV,
+ },
+
+ {
+ .n = "imgpll_fracck",
+ .p = "mainck",
+ .l = &pll_layout_frac,
+ .t = PLL_TYPE_FRAC,
+ .id = 3,
+ .cid = ID_PLL_IMG_FRAC,
+ },
+
+ {
+ .n = "imgpll_divpmcck",
+ .p = "imgpll_fracck",
+ .l = &pll_layout_divpmc,
+ .t = PLL_TYPE_DIV,
+ .id = 3,
+ .cid = ID_PLL_IMG_DIV
+ },
+
+ {
+ .n = "baudpll_fracck",
+ .p = "mainck",
+ .l = &pll_layout_frac,
+ .t = PLL_TYPE_FRAC,
+ .id = 4,
+ .cid = ID_PLL_BAUD_FRAC,
+ },
+
+ {
+ .n = "baudpll_divpmcck",
+ .p = "baudpll_fracck",
+ .l = &pll_layout_divpmc,
+ .t = PLL_TYPE_DIV,
+ .id = 4,
+ .cid = ID_PLL_BAUD_DIV,
+ },
+
+ {
+ .n = "audiopll_fracck",
+ .p = "main_osc",
+ .l = &pll_layout_frac,
+ .t = PLL_TYPE_FRAC,
+ .id = 5,
+ .cid = ID_PLL_AUDIO_FRAC,
+ },
+
+ {
+ .n = "audiopll_divpmcck",
+ .p = "audiopll_fracck",
+ .l = &pll_layout_divpmc,
+ .t = PLL_TYPE_DIV,
+ .id = 5,
+ .cid = ID_PLL_AUDIO_DIVPMC,
+ },
+
+ {
+ .n = "audiopll_diviock",
+ .p = "audiopll_fracck",
+ .l = &pll_layout_divio,
+ .t = PLL_TYPE_DIV,
+ .id = 5,
+ .cid = ID_PLL_AUDIO_DIVIO,
+ },
+
+ {
+ .n = "ethpll_fracck",
+ .p = "main_osc",
+ .l = &pll_layout_frac,
+ .t = PLL_TYPE_FRAC,
+ .id = 6,
+ .cid = ID_PLL_ETH_FRAC,
+ },
+
+ {
+ .n = "ethpll_divpmcck",
+ .p = "ethpll_fracck",
+ .l = &pll_layout_divpmc,
+ .t = PLL_TYPE_DIV,
+ .id = 6,
+ .cid = ID_PLL_ETH_DIV,
+ },
+};
+
+/**
+ * Master clock (MCK[1..4]) description
+ * @n: clock name
+ * @ep: extra parents names array
+ * @ep_chg_chg_id: index in parents array that specifies the changeable
+ * parent
+ * @ep_count: extra parents count
+ * @ep_mux_table: mux table for extra parents
+ * @ep_clk_mux_table: mux table to deal with subsystem clock ids
+ * @id: clock id corresponding to MCK driver
+ * @cid: clock id corresponding to clock subsystem
+ * @c: true if clock is critical and cannot be disabled
+ */
+static const struct {
+ const char *n;
+ const char *ep[4];
+ u8 ep_count;
+ u8 ep_mux_table[4];
+ u8 ep_clk_mux_table[4];
+ u8 id;
+ u8 cid;
+ u8 c;
+} sama7g5_mckx[] = {
+ {
+ .n = "mck1",
+ .id = 1,
+ .cid = ID_MCK1,
+ .ep = { "syspll_divpmcck", },
+ .ep_mux_table = { 5, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, },
+ .ep_count = 1,
+ .c = 1,
+ },
+
+ {
+ .n = "mck2",
+ .id = 2,
+ .cid = ID_MCK2,
+ .ep = { "ddrpll_divpmcck", },
+ .ep_mux_table = { 6, },
+ .ep_clk_mux_table = { ID_PLL_DDR_DIV, },
+ .ep_count = 1,
+ .c = 1,
+ },
+
+ {
+ .n = "mck3",
+ .id = 3,
+ .cid = ID_MCK3,
+ .ep = { "syspll_divpmcck", "ddrpll_divpmcck", "imgpll_divpmcck", },
+ .ep_mux_table = { 5, 6, 7, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_DDR_DIV, ID_PLL_IMG_DIV, },
+ .ep_count = 3,
+ },
+
+ {
+ .n = "mck4",
+ .id = 4,
+ .cid = ID_MCK4,
+ .ep = { "syspll_divpmcck", },
+ .ep_mux_table = { 5, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, },
+ .ep_count = 1,
+ .c = 1,
+ },
+};
+
+/**
+ * Programmable clock description
+ * @n: clock name
+ * @cid: clock id corresponding to clock subsystem
+ */
+static const struct {
+ const char *n;
+ u8 cid;
+} sama7g5_prog[] = {
+ { .n = "prog0", .cid = ID_PROG0, },
+ { .n = "prog1", .cid = ID_PROG1, },
+ { .n = "prog2", .cid = ID_PROG2, },
+ { .n = "prog3", .cid = ID_PROG3, },
+ { .n = "prog4", .cid = ID_PROG4, },
+ { .n = "prog5", .cid = ID_PROG5, },
+ { .n = "prog6", .cid = ID_PROG6, },
+ { .n = "prog7", .cid = ID_PROG7, },
+};
+
+/* Mux table for programmable clocks. */
+static u32 sama7g5_prog_mux_table[] = { 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, };
+
+/**
+ * System clock description
+ * @n: clock name
+ * @p: parent clock name
+ * @id: clock id corresponding to system clock driver
+ * @cid: clock id corresponding to clock subsystem
+ */
+static const struct {
+ const char *n;
+ const char *p;
+ u8 id;
+ u8 cid;
+} sama7g5_systemck[] = {
+ { .n = "pck0", .p = "prog0", .id = 8, .cid = ID_PCK0, },
+ { .n = "pck1", .p = "prog1", .id = 9, .cid = ID_PCK1, },
+ { .n = "pck2", .p = "prog2", .id = 10, .cid = ID_PCK2, },
+ { .n = "pck3", .p = "prog3", .id = 11, .cid = ID_PCK3, },
+ { .n = "pck4", .p = "prog4", .id = 12, .cid = ID_PCK4, },
+ { .n = "pck5", .p = "prog5", .id = 13, .cid = ID_PCK5, },
+ { .n = "pck6", .p = "prog6", .id = 14, .cid = ID_PCK6, },
+ { .n = "pck7", .p = "prog7", .id = 15, .cid = ID_PCK7, },
+};
+
+/**
+ * Peripheral clock description
+ * @n: clock name
+ * @p: clock parent name
+ * @r: clock range values
+ * @id: clock id
+ */
+static const struct {
+ const char *n;
+ const char *p;
+ struct clk_range r;
+ u8 id;
+} sama7g5_periphck[] = {
+ { .n = "pioA_clk", .p = "mck0", .id = 11, },
+ { .n = "sfr_clk", .p = "mck1", .id = 19, },
+ { .n = "hsmc_clk", .p = "mck1", .id = 21, },
+ { .n = "xdmac0_clk", .p = "mck1", .id = 22, },
+ { .n = "xdmac1_clk", .p = "mck1", .id = 23, },
+ { .n = "xdmac2_clk", .p = "mck1", .id = 24, },
+ { .n = "acc_clk", .p = "mck1", .id = 25, },
+ { .n = "aes_clk", .p = "mck1", .id = 27, },
+ { .n = "tzaesbasc_clk", .p = "mck1", .id = 28, },
+ { .n = "asrc_clk", .p = "mck1", .id = 30, .r = { .max = 200000000, }, },
+ { .n = "cpkcc_clk", .p = "mck0", .id = 32, },
+ { .n = "csi_clk", .p = "mck3", .id = 33, .r = { .max = 266000000, }, },
+ { .n = "csi2dc_clk", .p = "mck3", .id = 34, .r = { .max = 266000000, }, },
+ { .n = "eic_clk", .p = "mck1", .id = 37, },
+ { .n = "flex0_clk", .p = "mck1", .id = 38, },
+ { .n = "flex1_clk", .p = "mck1", .id = 39, },
+ { .n = "flex2_clk", .p = "mck1", .id = 40, },
+ { .n = "flex3_clk", .p = "mck1", .id = 41, },
+ { .n = "flex4_clk", .p = "mck1", .id = 42, },
+ { .n = "flex5_clk", .p = "mck1", .id = 43, },
+ { .n = "flex6_clk", .p = "mck1", .id = 44, },
+ { .n = "flex7_clk", .p = "mck1", .id = 45, },
+ { .n = "flex8_clk", .p = "mck1", .id = 46, },
+ { .n = "flex9_clk", .p = "mck1", .id = 47, },
+ { .n = "flex10_clk", .p = "mck1", .id = 48, },
+ { .n = "flex11_clk", .p = "mck1", .id = 49, },
+ { .n = "gmac0_clk", .p = "mck1", .id = 51, },
+ { .n = "gmac1_clk", .p = "mck1", .id = 52, },
+ { .n = "gmac0_tsu_clk", .p = "mck1", .id = 53, },
+ { .n = "gmac1_tsu_clk", .p = "mck1", .id = 54, },
+ { .n = "icm_clk", .p = "mck1", .id = 55, },
+ { .n = "isc_clk", .p = "mck3", .id = 56, .r = { .max = 266000000, }, },
+ { .n = "i2smcc0_clk", .p = "mck1", .id = 57, .r = { .max = 200000000, }, },
+ { .n = "i2smcc1_clk", .p = "mck1", .id = 58, .r = { .max = 200000000, }, },
+ { .n = "matrix_clk", .p = "mck1", .id = 60, },
+ { .n = "mcan0_clk", .p = "mck1", .id = 61, .r = { .max = 200000000, }, },
+ { .n = "mcan1_clk", .p = "mck1", .id = 62, .r = { .max = 200000000, }, },
+ { .n = "mcan2_clk", .p = "mck1", .id = 63, .r = { .max = 200000000, }, },
+ { .n = "mcan3_clk", .p = "mck1", .id = 64, .r = { .max = 200000000, }, },
+ { .n = "mcan4_clk", .p = "mck1", .id = 65, .r = { .max = 200000000, }, },
+ { .n = "mcan5_clk", .p = "mck1", .id = 66, .r = { .max = 200000000, }, },
+ { .n = "pdmc0_clk", .p = "mck1", .id = 68, .r = { .max = 200000000, }, },
+ { .n = "pdmc1_clk", .p = "mck1", .id = 69, .r = { .max = 200000000, }, },
+ { .n = "pit64b0_clk", .p = "mck1", .id = 70, },
+ { .n = "pit64b1_clk", .p = "mck1", .id = 71, },
+ { .n = "pit64b2_clk", .p = "mck1", .id = 72, },
+ { .n = "pit64b3_clk", .p = "mck1", .id = 73, },
+ { .n = "pit64b4_clk", .p = "mck1", .id = 74, },
+ { .n = "pit64b5_clk", .p = "mck1", .id = 75, },
+ { .n = "pwm_clk", .p = "mck1", .id = 77, },
+ { .n = "qspi0_clk", .p = "mck1", .id = 78, },
+ { .n = "qspi1_clk", .p = "mck1", .id = 79, },
+ { .n = "sdmmc0_clk", .p = "mck1", .id = 80, },
+ { .n = "sdmmc1_clk", .p = "mck1", .id = 81, },
+ { .n = "sdmmc2_clk", .p = "mck1", .id = 82, },
+ { .n = "sha_clk", .p = "mck1", .id = 83, },
+ { .n = "spdifrx_clk", .p = "mck1", .id = 84, .r = { .max = 200000000, }, },
+ { .n = "spdiftx_clk", .p = "mck1", .id = 85, .r = { .max = 200000000, }, },
+ { .n = "ssc0_clk", .p = "mck1", .id = 86, .r = { .max = 200000000, }, },
+ { .n = "ssc1_clk", .p = "mck1", .id = 87, .r = { .max = 200000000, }, },
+ { .n = "tcb0_ch0_clk", .p = "mck1", .id = 88, .r = { .max = 200000000, }, },
+ { .n = "tcb0_ch1_clk", .p = "mck1", .id = 89, .r = { .max = 200000000, }, },
+ { .n = "tcb0_ch2_clk", .p = "mck1", .id = 90, .r = { .max = 200000000, }, },
+ { .n = "tcb1_ch0_clk", .p = "mck1", .id = 91, .r = { .max = 200000000, }, },
+ { .n = "tcb1_ch1_clk", .p = "mck1", .id = 92, .r = { .max = 200000000, }, },
+ { .n = "tcb1_ch2_clk", .p = "mck1", .id = 93, .r = { .max = 200000000, }, },
+ { .n = "tcpca_clk", .p = "mck1", .id = 94, },
+ { .n = "tcpcb_clk", .p = "mck1", .id = 95, },
+ { .n = "tdes_clk", .p = "mck1", .id = 96, },
+ { .n = "trng_clk", .p = "mck1", .id = 97, },
+ { .n = "udphsa_clk", .p = "mck1", .id = 104, },
+ { .n = "udphsb_clk", .p = "mck1", .id = 105, },
+ { .n = "uhphs_clk", .p = "mck1", .id = 106, },
+};
+
+/**
+ * Generic clock description
+ * @n: clock name
+ * @ep: extra parents names
+ * @ep_mux_table: extra parents mux table
+ * @ep_clk_mux_table: extra parents clock mux table (for CCF)
+ * @r: clock output range
+ * @ep_count: extra parents count
+ * @id: clock id
+ */
+static const struct {
+ const char *n;
+ const char *ep[8];
+ const char ep_mux_table[8];
+ const char ep_clk_mux_table[8];
+ struct clk_range r;
+ u8 ep_count;
+ u8 id;
+} sama7g5_gck[] = {
+ {
+ .n = "adc_gclk",
+ .id = 26,
+ .r = { .max = 100000000, },
+ .ep = { "syspll_divpmcck", "imgpll_divpmcck", "audiopll_divpmcck", },
+ .ep_mux_table = { 5, 7, 9, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV,
+ ID_PLL_AUDIO_DIVPMC, },
+ .ep_count = 3,
+ },
+
+ {
+ .n = "asrc_gclk",
+ .id = 30,
+ .r = { .max = 200000000 },
+ .ep = { "audiopll_divpmcck", },
+ .ep_mux_table = { 9, },
+ .ep_clk_mux_table = { ID_PLL_AUDIO_DIVPMC, },
+ .ep_count = 1,
+ },
+
+ {
+ .n = "csi_gclk",
+ .id = 33,
+ .r = { .max = 27000000 },
+ .ep = { "ddrpll_divpmcck", "imgpll_divpmcck", },
+ .ep_clk_mux_table = { ID_PLL_DDR_DIV, ID_PLL_IMG_DIV, },
+ .ep_mux_table = { 6, 7, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex0_gclk",
+ .id = 38,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex1_gclk",
+ .id = 39,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex2_gclk",
+ .id = 40,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex3_gclk",
+ .id = 41,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex4_gclk",
+ .id = 42,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex5_gclk",
+ .id = 43,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex6_gclk",
+ .id = 44,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex7_gclk",
+ .id = 45,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex8_gclk",
+ .id = 46,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex9_gclk",
+ .id = 47,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex10_gclk",
+ .id = 48,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex11_gclk",
+ .id = 49,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "gmac0_gclk",
+ .id = 51,
+ .r = { .max = 125000000 },
+ .ep = { "ethpll_divpmcck", },
+ .ep_clk_mux_table = { ID_PLL_ETH_DIV, },
+ .ep_mux_table = { 10, },
+ .ep_count = 1,
+ },
+
+ {
+ .n = "gmac1_gclk",
+ .id = 52,
+ .r = { .max = 50000000 },
+ .ep = { "ethpll_divpmcck", },
+ .ep_mux_table = { 10, },
+ .ep_clk_mux_table = { ID_PLL_ETH_DIV, },
+ .ep_count = 1,
+ },
+
+ {
+ .n = "gmac0_tsu_gclk",
+ .id = 53,
+ .r = { .max = 300000000 },
+ .ep = { "audiopll_divpmcck", "ethpll_divpmcck", },
+ .ep_mux_table = { 9, 10, },
+ .ep_clk_mux_table = { ID_PLL_AUDIO_DIVPMC, ID_PLL_ETH_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "gmac1_tsu_gclk",
+ .id = 54,
+ .r = { .max = 300000000 },
+ .ep = { "audiopll_divpmcck", "ethpll_divpmcck", },
+ .ep_mux_table = { 9, 10, },
+ .ep_clk_mux_table = { ID_PLL_AUDIO_DIVPMC, ID_PLL_ETH_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "i2smcc0_gclk",
+ .id = 57,
+ .r = { .max = 100000000 },
+ .ep = { "syspll_divpmcck", "audiopll_divpmcck", },
+ .ep_mux_table = { 5, 9, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_AUDIO_DIVPMC, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "i2smcc1_gclk",
+ .id = 58,
+ .r = { .max = 100000000 },
+ .ep = { "syspll_divpmcck", "audiopll_divpmcck", },
+ .ep_mux_table = { 5, 9, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_AUDIO_DIVPMC, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "mcan0_gclk",
+ .id = 61,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "mcan1_gclk",
+ .id = 62,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "mcan2_gclk",
+ .id = 63,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "mcan3_gclk",
+ .id = 64,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "mcan4_gclk",
+ .id = 65,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "mcan5_gclk",
+ .id = 66,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "pdmc0_gclk",
+ .id = 68,
+ .r = { .max = 50000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "pdmc1_gclk",
+ .id = 69,
+ .r = { .max = 50000000, },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "pit64b0_gclk",
+ .id = 70,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+ "audiopll_divpmcck", "ethpll_divpmcck", },
+ .ep_mux_table = { 5, 7, 8, 9, 10, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV,
+ ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC,
+ ID_PLL_ETH_DIV, },
+ .ep_count = 5,
+ },
+
+ {
+ .n = "pit64b1_gclk",
+ .id = 71,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+ "audiopll_divpmcck", "ethpll_divpmcck", },
+ .ep_mux_table = { 5, 7, 8, 9, 10, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV,
+ ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC,
+ ID_PLL_ETH_DIV, },
+ .ep_count = 5,
+ },
+
+ {
+ .n = "pit64b2_gclk",
+ .id = 72,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+ "audiopll_divpmcck", "ethpll_divpmcck", },
+ .ep_mux_table = { 5, 7, 8, 9, 10, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV,
+ ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC,
+ ID_PLL_ETH_DIV, },
+ .ep_count = 5,
+ },
+
+ {
+ .n = "pit64b3_gclk",
+ .id = 73,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+ "audiopll_divpmcck", "ethpll_divpmcck", },
+ .ep_mux_table = { 5, 7, 8, 9, 10, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV,
+ ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC,
+ ID_PLL_ETH_DIV, },
+ .ep_count = 5,
+ },
+
+ {
+ .n = "pit64b4_gclk",
+ .id = 74,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+ "audiopll_divpmcck", "ethpll_divpmcck", },
+ .ep_mux_table = { 5, 7, 8, 9, 10, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV,
+ ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC,
+ ID_PLL_ETH_DIV, },
+ .ep_count = 5,
+ },
+
+ {
+ .n = "pit64b5_gclk",
+ .id = 75,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+ "audiopll_divpmcck", "ethpll_divpmcck", },
+ .ep_mux_table = { 5, 7, 8, 9, 10, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV,
+ ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC,
+ ID_PLL_ETH_DIV, },
+ .ep_count = 5,
+ },
+
+ {
+ .n = "qspi0_gclk",
+ .id = 78,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV,
+ ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC,
+ ID_PLL_ETH_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "qspi1_gclk",
+ .id = 79,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "sdmmc0_gclk",
+ .id = 80,
+ .r = { .max = 208000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "sdmmc1_gclk",
+ .id = 81,
+ .r = { .max = 208000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "sdmmc2_gclk",
+ .id = 82,
+ .r = { .max = 208000000 },
+ .ep = { "syspll_divpmcck", "baudpll_divpmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_BAUD_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "spdifrx_gclk",
+ .id = 84,
+ .r = { .max = 150000000 },
+ .ep = { "syspll_divpmcck", "audiopll_divpmcck", },
+ .ep_mux_table = { 5, 9, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_AUDIO_DIVPMC, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "spdiftx_gclk",
+ .id = 85,
+ .r = { .max = 25000000 },
+ .ep = { "syspll_divpmcck", "audiopll_divpmcck", },
+ .ep_mux_table = { 5, 9, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_AUDIO_DIVPMC, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "tcb0_ch0_gclk",
+ .id = 88,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+ "audiopll_divpmcck", "ethpll_divpmcck", },
+ .ep_mux_table = { 5, 7, 8, 9, 10, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV,
+ ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC,
+ ID_PLL_ETH_DIV, },
+ .ep_count = 5,
+ },
+
+ {
+ .n = "tcb1_ch0_gclk",
+ .id = 91,
+ .r = { .max = 200000000 },
+ .ep = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck",
+ "audiopll_divpmcck", "ethpll_divpmcck", },
+ .ep_mux_table = { 5, 7, 8, 9, 10, },
+ .ep_clk_mux_table = { ID_PLL_SYS_DIV, ID_PLL_IMG_DIV,
+ ID_PLL_BAUD_DIV, ID_PLL_AUDIO_DIVPMC,
+ ID_PLL_ETH_DIV, },
+ .ep_count = 5,
+ },
+};
+
+/**
+ * Clock setup description
+ * @cid: clock id corresponding to clock subsystem
+ * @pid: parent clock id corresponding to clock subsystem
+ * @rate: clock rate
+ * @prate: parent rate
+ */
+static const struct pmc_clk_setup {
+ unsigned int cid;
+ unsigned int pid;
+ unsigned long rate;
+ unsigned long prate;
+} sama7g5_clk_setup[] = {
+ {
+ .cid = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_ETH_FRAC),
+ .rate = 625000000,
+ },
+
+ {
+ .cid = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_ETH_DIV),
+ .rate = 625000000,
+ },
+};
+
+#define SAMA7G5_MAX_MUX_ALLOCS (64)
+
+#define prepare_mux_table(_allocs, _index, _dst, _src, _num, _label) \
+ do { \
+ int _i; \
+ if ((_index) >= SAMA7G5_MAX_MUX_ALLOCS) { \
+ debug("%s(): AT91: MUX: insufficient space\n", \
+ __func__); \
+ goto _label; \
+ } \
+ (_dst) = kzalloc(sizeof(*(_dst)) * (_num), GFP_KERNEL); \
+ if (!(_dst)) \
+ goto _label; \
+ (_allocs)[(_index)++] = (_dst); \
+ for (_i = 0; _i < (_num); _i++) \
+ (_dst)[_i] = (_src)[_i]; \
+ } while (0)
+
+static int sama7g5_clk_probe(struct udevice *dev)
+{
+ void __iomem *base = (void *)devfdt_get_addr(dev);
+ unsigned int *clkmuxallocs[SAMA7G5_MAX_MUX_ALLOCS];
+ unsigned int *muxallocs[SAMA7G5_MAX_MUX_ALLOCS];
+ const char *p[10];
+ unsigned int cm[10], m[10], *tmpclkmux, *tmpmux;
+ struct clk clk, *c, *parent;
+ bool main_osc_bypass;
+ int ret, muxallocindex = 0, clkmuxallocindex = 0, i, j;
+
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ memset(muxallocs, 0, ARRAY_SIZE(muxallocs));
+ memset(clkmuxallocs, 0, ARRAY_SIZE(clkmuxallocs));
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret)
+ return ret;
+ ret = clk_get_by_id(clk.id, &c);
+ if (ret)
+ return ret;
+ clk_names[ID_TD_SLCK] = kmemdup(clk_hw_get_name(c),
+ strlen(clk_hw_get_name(c)) + 1, GFP_KERNEL);
+ if (!clk_names[ID_TD_SLCK])
+ return -ENOMEM;
+
+ ret = clk_get_by_index(dev, 1, &clk);
+ if (ret)
+ return ret;
+ ret = clk_get_by_id(clk.id, &c);
+ if (ret)
+ return ret;
+ clk_names[ID_MD_SLCK] = kmemdup(clk_hw_get_name(c),
+ strlen(clk_hw_get_name(c)) + 1, GFP_KERNEL);
+ if (!clk_names[ID_MD_SLCK])
+ return -ENOMEM;
+
+ ret = clk_get_by_index(dev, 2, &clk);
+ if (ret)
+ return ret;
+ clk_names[ID_MAIN_XTAL] = kmemdup(clk_hw_get_name(&clk),
+ strlen(clk_hw_get_name(&clk)) + 1, GFP_KERNEL);
+ if (!clk_names[ID_MAIN_XTAL])
+ return -ENOMEM;
+
+ ret = clk_get_by_index(dev, 3, &clk);
+ if (ret)
+ goto fail;
+ clk_names[ID_MAIN_RC] = kmemdup(clk_hw_get_name(&clk),
+ strlen(clk_hw_get_name(&clk)) + 1, GFP_KERNEL);
+ if (ret)
+ goto fail;
+
+ main_osc_bypass = dev_read_bool(dev, "atmel,main-osc-bypass");
+
+ /* Register main rc oscillator. */
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAIN_RC_OSC),
+ at91_clk_main_rc(base, clk_names[ID_MAIN_RC_OSC],
+ clk_names[ID_MAIN_RC]));
+
+ /* Register main oscillator. */
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAIN_OSC),
+ at91_clk_main_osc(base, clk_names[ID_MAIN_OSC],
+ clk_names[ID_MAIN_XTAL], main_osc_bypass));
+
+ /* Register mainck. */
+ p[0] = clk_names[ID_MAIN_RC_OSC];
+ p[1] = clk_names[ID_MAIN_OSC];
+ cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAIN_RC_OSC);
+ cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAIN_OSC);
+ prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm, 2,
+ fail);
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAINCK),
+ at91_clk_sam9x5_main(base, clk_names[ID_MAINCK], p,
+ 2, tmpclkmux, PMC_TYPE_CORE));
+
+ /* Register PLL fracs clocks. */
+ for (i = 0; i < ARRAY_SIZE(sama7g5_plls); i++) {
+ if (sama7g5_plls[i].t != PLL_TYPE_FRAC)
+ continue;
+
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, sama7g5_plls[i].cid),
+ sam9x60_clk_register_frac_pll(base, sama7g5_plls[i].n,
+ sama7g5_plls[i].p, sama7g5_plls[i].id,
+ &pll_characteristics, sama7g5_plls[i].l,
+ sama7g5_plls[i].c));
+ }
+
+ /* Register PLL div clocks. */
+ for (i = 0; i < ARRAY_SIZE(sama7g5_plls); i++) {
+ if (sama7g5_plls[i].t != PLL_TYPE_DIV)
+ continue;
+
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, sama7g5_plls[i].cid),
+ sam9x60_clk_register_div_pll(base, sama7g5_plls[i].n,
+ sama7g5_plls[i].p, sama7g5_plls[i].id,
+ &pll_characteristics, sama7g5_plls[i].l,
+ sama7g5_plls[i].c));
+ }
+
+ /* Register MCK0 clock. */
+ p[0] = clk_names[ID_MD_SLCK];
+ p[1] = clk_names[ID_MAINCK];
+ p[2] = clk_names[ID_PLL_CPU_DIV];
+ p[3] = clk_names[ID_PLL_SYS_DIV];
+ cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MD_SLCK);
+ cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAINCK);
+ cm[2] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_CPU_DIV);
+ cm[3] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_SYS_DIV);
+ prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm, 2,
+ fail);
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MCK0),
+ at91_clk_register_master(base, clk_names[ID_MCK0], p,
+ 4, &mck0_layout, &mck0_characteristics, tmpclkmux));
+
+ /* Register MCK1-4 clocks. */
+ p[0] = clk_names[ID_MD_SLCK];
+ p[1] = clk_names[ID_TD_SLCK];
+ p[2] = clk_names[ID_MAINCK];
+ p[3] = clk_names[ID_MCK0];
+ m[0] = 0;
+ m[1] = 1;
+ m[2] = 2;
+ m[3] = 3;
+ cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MD_SLCK);
+ cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_TD_SLCK);
+ cm[2] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAINCK);
+ cm[3] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MCK0);
+ for (i = 0; i < ARRAY_SIZE(sama7g5_mckx); i++) {
+ for (j = 0; j < sama7g5_mckx[i].ep_count; j++) {
+ p[4 + j] = sama7g5_mckx[i].ep[j];
+ m[4 + j] = sama7g5_mckx[i].ep_mux_table[j];
+ cm[4 + j] = AT91_TO_CLK_ID(PMC_TYPE_CORE,
+ sama7g5_mckx[i].ep_clk_mux_table[j]);
+ }
+
+ prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm,
+ 4 + sama7g5_mckx[i].ep_count, fail);
+ prepare_mux_table(muxallocs, muxallocindex, tmpmux, m,
+ 4 + sama7g5_mckx[i].ep_count, fail);
+
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, sama7g5_mckx[i].cid),
+ at91_clk_sama7g5_register_master(base,
+ sama7g5_mckx[i].n, p, 4 + sama7g5_mckx[i].ep_count,
+ tmpmux, tmpclkmux, sama7g5_mckx[i].c,
+ sama7g5_mckx[i].id));
+ }
+
+ /* Register UTMI clock. */
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_UTMI),
+ at91_clk_sama7g5_register_utmi(base, "utmick",
+ clk_names[ID_MAIN_XTAL]));
+
+ /* Register programmable clocks. */
+ p[0] = clk_names[ID_MD_SLCK];
+ p[1] = clk_names[ID_TD_SLCK];
+ p[2] = clk_names[ID_MAINCK];
+ p[3] = clk_names[ID_MCK0];
+ p[4] = clk_names[ID_PLL_SYS_DIV];
+ p[5] = clk_names[ID_PLL_DDR_DIV];
+ p[6] = clk_names[ID_PLL_IMG_DIV];
+ p[7] = clk_names[ID_PLL_BAUD_DIV];
+ p[8] = clk_names[ID_PLL_AUDIO_DIVPMC];
+ p[9] = clk_names[ID_PLL_ETH_DIV];
+ cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MD_SLCK);
+ cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_TD_SLCK);
+ cm[2] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAINCK);
+ cm[3] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MCK0);
+ cm[4] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_SYS_DIV);
+ cm[5] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_DDR_DIV);
+ cm[6] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_IMG_DIV);
+ cm[7] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_BAUD_DIV);
+ cm[8] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_AUDIO_DIVPMC);
+ cm[9] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_ETH_DIV);
+ for (i = 0; i < ARRAY_SIZE(sama7g5_prog); i++) {
+ prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm,
+ 10, fail);
+
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, sama7g5_prog[i].cid),
+ at91_clk_register_programmable(base, sama7g5_prog[i].n,
+ p, 10, i, &programmable_layout, tmpclkmux,
+ sama7g5_prog_mux_table));
+ }
+
+ /* System clocks. */
+ for (i = 0; i < ARRAY_SIZE(sama7g5_systemck); i++) {
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_SYSTEM, sama7g5_systemck[i].cid),
+ at91_clk_register_system(base, sama7g5_systemck[i].n,
+ sama7g5_systemck[i].p, sama7g5_systemck[i].id));
+ }
+
+ /* Peripheral clocks. */
+ for (i = 0; i < ARRAY_SIZE(sama7g5_periphck); i++) {
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_PERIPHERAL,
+ sama7g5_periphck[i].id),
+ at91_clk_register_sam9x5_peripheral(base,
+ &sama7g5_pcr_layout, sama7g5_periphck[i].n,
+ sama7g5_periphck[i].p, sama7g5_periphck[i].id,
+ &sama7g5_periphck[i].r));
+ }
+
+ /* Generic clocks. */
+ p[0] = clk_names[ID_MD_SLCK];
+ p[1] = clk_names[ID_TD_SLCK];
+ p[2] = clk_names[ID_MAINCK];
+ p[3] = clk_names[ID_MCK0];
+ m[0] = 0;
+ m[1] = 1;
+ m[2] = 2;
+ m[3] = 3;
+ cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MD_SLCK);
+ cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_TD_SLCK);
+ cm[2] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAINCK);
+ cm[3] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MCK0);
+ for (i = 0; i < ARRAY_SIZE(sama7g5_gck); i++) {
+ for (j = 0; j < sama7g5_gck[i].ep_count; j++) {
+ p[4 + j] = sama7g5_gck[i].ep[j];
+ m[4 + j] = sama7g5_gck[i].ep_mux_table[j];
+ cm[4 + j] = AT91_TO_CLK_ID(PMC_TYPE_CORE,
+ sama7g5_gck[i].ep_clk_mux_table[j]);
+ }
+
+ prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm,
+ 4 + sama7g5_gck[i].ep_count, fail);
+ prepare_mux_table(muxallocs, muxallocindex, tmpmux, m,
+ 4 + sama7g5_gck[i].ep_count, fail);
+
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_GCK, sama7g5_gck[i].id),
+ at91_clk_register_generic(base, &sama7g5_pcr_layout,
+ sama7g5_gck[i].n, p, tmpclkmux, tmpmux,
+ 4 + sama7g5_gck[i].ep_count, sama7g5_gck[i].id,
+ &sama7g5_gck[i].r));
+ }
+
+ /* Setup clocks. */
+ for (i = 0; i < ARRAY_SIZE(sama7g5_clk_setup); i++) {
+ ret = clk_get_by_id(sama7g5_clk_setup[i].cid, &c);
+ if (ret)
+ goto fail;
+
+ if (sama7g5_clk_setup[i].pid) {
+ ret = clk_get_by_id(sama7g5_clk_setup[i].pid, &parent);
+ if (ret)
+ goto fail;
+
+ ret = clk_set_parent(c, parent);
+ if (ret)
+ goto fail;
+
+ if (sama7g5_clk_setup[i].prate) {
+ ret = clk_set_rate(parent,
+ sama7g5_clk_setup[i].prate);
+ if (ret < 0)
+ goto fail;
+ }
+ }
+
+ if (sama7g5_clk_setup[i].rate) {
+ ret = clk_set_rate(c, sama7g5_clk_setup[i].rate);
+ if (ret < 0)
+ goto fail;
+ }
+ }
+
+ return 0;
+
+fail:
+ for (i = 0; i < ARRAY_SIZE(muxallocs); i++)
+ kfree(muxallocs[i]);
+
+ for (i = 0; i < ARRAY_SIZE(clkmuxallocs); i++)
+ kfree(clkmuxallocs[i]);
+
+ return -ENOMEM;
+}
+
+static const struct udevice_id sama7g5_clk_ids[] = {
+ { .compatible = "microchip,sama7g5-pmc" },
+ { /* Sentinel. */ },
+};
+
+U_BOOT_DRIVER(at91_sama7g5_pmc) = {
+ .name = "at91-sama7g5-pmc",
+ .id = UCLASS_CLK,
+ .of_match = sama7g5_clk_ids,
+ .ops = &at91_clk_ops,
+ .probe = sama7g5_clk_probe,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c
index a879b008ffd..dd62dc5510e 100644
--- a/drivers/clk/at91/sckc.c
+++ b/drivers/clk/at91/sckc.c
@@ -1,19 +1,172 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright (C) 2016 Atmel Corporation
- * Wenyou.Yang <wenyou.yang@atmel.com>
+ * Slow clock support for AT91 architectures.
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
*/
#include <common.h>
+#include <clk-uclass.h>
#include <dm.h>
+#include <dt-bindings/clk/at91.h>
+#include <linux/clk-provider.h>
-static const struct udevice_id at91_sckc_match[] = {
- { .compatible = "atmel,at91sam9x5-sckc" },
- {}
+#include "pmc.h"
+
+#define UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK "at91-sam9x60-td-slck"
+#define UBOOT_DM_CLK_AT91_SCKC "at91-sckc"
+
+#define AT91_OSC_SEL BIT(24)
+#define AT91_OSC_SEL_SHIFT (24)
+
+struct sam9x60_sckc {
+ void __iomem *reg;
+ const char **parent_names;
+ unsigned int num_parents;
+ struct clk clk;
+};
+
+#define to_sam9x60_sckc(c) container_of(c, struct sam9x60_sckc, clk)
+
+static int sam9x60_sckc_of_xlate(struct clk *clk,
+ struct ofnode_phandle_args *args)
+{
+ if (args->args_count != 1) {
+ debug("AT91: SCKC: Invalid args_count: %d\n", args->args_count);
+ return -EINVAL;
+ }
+
+ clk->id = AT91_TO_CLK_ID(PMC_TYPE_SLOW, args->args[0]);
+
+ return 0;
+}
+
+static const struct clk_ops sam9x60_sckc_ops = {
+ .of_xlate = sam9x60_sckc_of_xlate,
+ .get_rate = clk_generic_get_rate,
+};
+
+static int sam9x60_td_slck_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct sam9x60_sckc *sckc = to_sam9x60_sckc(clk);
+ u32 i;
+
+ for (i = 0; i < sckc->num_parents; i++) {
+ if (!strcmp(parent->dev->name, sckc->parent_names[i]))
+ break;
+ }
+ if (i == sckc->num_parents)
+ return -EINVAL;
+
+ pmc_update_bits(sckc->reg, 0, AT91_OSC_SEL, (i << AT91_OSC_SEL_SHIFT));
+
+ return 0;
+}
+
+static const struct clk_ops sam9x60_td_slck_ops = {
+ .get_rate = clk_generic_get_rate,
+ .set_parent = sam9x60_td_slck_set_parent,
+};
+
+static struct clk *at91_sam9x60_clk_register_td_slck(struct sam9x60_sckc *sckc,
+ const char *name, const char * const *parent_names,
+ int num_parents)
+{
+ struct clk *clk;
+ int ret = -ENOMEM;
+ u32 val, i;
+
+ if (!sckc || !name || !parent_names || num_parents != 2)
+ return ERR_PTR(-EINVAL);
+
+ sckc->parent_names = kzalloc(sizeof(*sckc->parent_names) * num_parents,
+ GFP_KERNEL);
+ if (!sckc->parent_names)
+ return ERR_PTR(ret);
+
+ for (i = 0; i < num_parents; i++) {
+ sckc->parent_names[i] = kmemdup(parent_names[i],
+ strlen(parent_names[i]) + 1, GFP_KERNEL);
+ if (!sckc->parent_names[i])
+ goto free;
+ }
+ sckc->num_parents = num_parents;
+
+ pmc_read(sckc->reg, 0, &val);
+ val = (val & AT91_OSC_SEL) >> AT91_OSC_SEL_SHIFT;
+
+ clk = &sckc->clk;
+ ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK, name,
+ parent_names[val]);
+ if (ret)
+ goto free;
+
+ return clk;
+
+free:
+ for (; i >= 0; i--)
+ kfree(sckc->parent_names[i]);
+ kfree(sckc->parent_names);
+
+ return ERR_PTR(ret);
+}
+
+U_BOOT_DRIVER(at91_sam9x60_td_slck) = {
+ .name = UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK,
+ .id = UCLASS_CLK,
+ .ops = &sam9x60_td_slck_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+static int at91_sam9x60_sckc_probe(struct udevice *dev)
+{
+ struct sam9x60_sckc *sckc = dev_get_priv(dev);
+ void __iomem *base = (void *)devfdt_get_addr(dev);
+ const char *slow_rc_osc, *slow_osc;
+ const char *parents[2];
+ struct clk *clk, c;
+ int ret;
+
+ ret = clk_get_by_index(dev, 0, &c);
+ if (ret)
+ return ret;
+ slow_rc_osc = clk_hw_get_name(&c);
+
+ ret = clk_get_by_index(dev, 1, &c);
+ if (ret)
+ return ret;
+ slow_osc = clk_hw_get_name(&c);
+
+ clk = clk_register_fixed_factor(NULL, "md_slck", slow_rc_osc, 0, 1, 1);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_SLOW, 0), clk);
+
+ parents[0] = slow_rc_osc;
+ parents[1] = slow_osc;
+ sckc[1].reg = base;
+ clk = at91_sam9x60_clk_register_td_slck(&sckc[1], "td_slck",
+ parents, 2);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_SLOW, 1), clk);
+
+ return 0;
+}
+
+static const struct udevice_id sam9x60_sckc_ids[] = {
+ { .compatible = "microchip,sam9x60-sckc" },
+ { /* Sentinel. */ },
};
U_BOOT_DRIVER(at91_sckc) = {
- .name = "at91-sckc",
- .id = UCLASS_SIMPLE_BUS,
- .of_match = at91_sckc_match,
+ .name = UBOOT_DM_CLK_AT91_SCKC,
+ .id = UCLASS_CLK,
+ .of_match = sam9x60_sckc_ids,
+ .priv_auto_alloc_size = sizeof(struct sam9x60_sckc) * 2,
+ .ops = &sam9x60_sckc_ops,
+ .probe = at91_sam9x60_sckc_probe,
+ .flags = DM_FLAG_PRE_RELOC,
};
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index 934cd5787a5..4076535271b 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -14,6 +14,7 @@
#include <errno.h>
#include <log.h>
#include <malloc.h>
+#include <dm/device-internal.h>
#include <dm/devres.h>
#include <dm/read.h>
#include <linux/bug.h>
@@ -187,9 +188,26 @@ bulk_get_err:
return ret;
}
+static struct clk *clk_set_default_get_by_id(struct clk *clk)
+{
+ struct clk *c = clk;
+
+ if (CONFIG_IS_ENABLED(CLK_CCF)) {
+ int ret = clk_get_by_id(clk->id, &c);
+
+ if (ret) {
+ debug("%s(): could not get parent clock pointer, id %lu\n",
+ __func__, clk->id);
+ ERR_PTR(ret);
+ }
+ }
+
+ return c;
+}
+
static int clk_set_default_parents(struct udevice *dev, int stage)
{
- struct clk clk, parent_clk;
+ struct clk clk, parent_clk, *c, *p;
int index;
int num_parents;
int ret;
@@ -215,6 +233,10 @@ static int clk_set_default_parents(struct udevice *dev, int stage)
return ret;
}
+ p = clk_set_default_get_by_id(&parent_clk);
+ if (IS_ERR(p))
+ return PTR_ERR(p);
+
ret = clk_get_by_indexed_prop(dev, "assigned-clocks",
index, &clk);
if (ret) {
@@ -234,7 +256,11 @@ static int clk_set_default_parents(struct udevice *dev, int stage)
/* do not setup twice the parent clocks */
continue;
- ret = clk_set_parent(&clk, &parent_clk);
+ c = clk_set_default_get_by_id(&clk);
+ if (IS_ERR(c))
+ return PTR_ERR(c);
+
+ ret = clk_set_parent(c, p);
/*
* Not all drivers may support clock-reparenting (as of now).
* Ignore errors due to this.
@@ -254,7 +280,7 @@ static int clk_set_default_parents(struct udevice *dev, int stage)
static int clk_set_default_rates(struct udevice *dev, int stage)
{
- struct clk clk;
+ struct clk clk, *c;
int index;
int num_rates;
int size;
@@ -298,7 +324,11 @@ static int clk_set_default_rates(struct udevice *dev, int stage)
/* do not setup twice the parent clocks */
continue;
- ret = clk_set_rate(&clk, rates[index]);
+ c = clk_set_default_get_by_id(&clk);
+ if (IS_ERR(c))
+ return PTR_ERR(c);
+
+ ret = clk_set_rate(c, rates[index]);
if (ret < 0) {
debug("%s: failed to set rate on clock index %d (%ld) for %s\n",
@@ -512,6 +542,7 @@ ulong clk_set_rate(struct clk *clk, ulong rate)
int clk_set_parent(struct clk *clk, struct clk *parent)
{
const struct clk_ops *ops;
+ int ret;
debug("%s(clk=%p, parent=%p)\n", __func__, clk, parent);
if (!clk_valid(clk))
@@ -521,7 +552,14 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
if (!ops->set_parent)
return -ENOSYS;
- return ops->set_parent(clk, parent);
+ ret = ops->set_parent(clk, parent);
+ if (ret)
+ return ret;
+
+ if (CONFIG_IS_ENABLED(CLK_CCF))
+ ret = device_reparent(clk->dev, parent->dev);
+
+ return ret;
}
int clk_enable(struct clk *clk)
@@ -597,6 +635,9 @@ int clk_disable(struct clk *clk)
if (CONFIG_IS_ENABLED(CLK_CCF)) {
if (clk->id && !clk_get_by_id(clk->id, &clkp)) {
+ if (clkp->flags & CLK_IS_CRITICAL)
+ return 0;
+
if (clkp->enable_count == 0) {
printf("clk %s already disabled\n",
clkp->dev->name);
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 786f4e887e7..319808d433f 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -57,6 +57,9 @@ ulong clk_generic_get_rate(struct clk *clk)
const char *clk_hw_get_name(const struct clk *hw)
{
+ assert(hw);
+ assert(hw->dev);
+
return hw->dev->name;
}
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 355dbd147a9..e90d70101c2 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -276,6 +276,28 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
return ret;
}
+int device_reparent(struct udevice *dev, struct udevice *new_parent)
+{
+ struct udevice *pos, *n;
+
+ assert(dev);
+ assert(new_parent);
+
+ list_for_each_entry_safe(pos, n, &dev->parent->child_head,
+ sibling_node) {
+ if (pos->driver != dev->driver)
+ continue;
+
+ list_del(&dev->sibling_node);
+ list_add_tail(&dev->sibling_node, &new_parent->child_head);
+ dev->parent = new_parent;
+
+ break;
+ }
+
+ return 0;
+}
+
static void *alloc_priv(int size, uint flags)
{
void *priv;
diff --git a/drivers/cpu/Makefile b/drivers/cpu/Makefile
index 0b5dbc7c88e..c8532637ca7 100644
--- a/drivers/cpu/Makefile
+++ b/drivers/cpu/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_CPU) += cpu-uclass.o
obj-$(CONFIG_ARCH_BMIPS) += bmips_cpu.o
obj-$(CONFIG_ARCH_IMX8) += imx8_cpu.o
+obj-$(CONFIG_ARCH_AT91) += at91_cpu.o
obj-$(CONFIG_CPU_MPC83XX) += mpc83xx_cpu.o
obj-$(CONFIG_CPU_RISCV) += riscv_cpu.o
obj-$(CONFIG_SANDBOX) += cpu_sandbox.o
diff --git a/drivers/cpu/at91_cpu.c b/drivers/cpu/at91_cpu.c
new file mode 100644
index 00000000000..058ae3a8119
--- /dev/null
+++ b/drivers/cpu/at91_cpu.c
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ */
+
+#include <common.h>
+#include <cpu.h>
+#include <dm.h>
+#include <div64.h>
+#include <linux/clk-provider.h>
+
+struct at91_cpu_platdata {
+ const char *name;
+ ulong cpufreq_mhz;
+ ulong mckfreq_mhz;
+ ulong xtalfreq_mhz;
+};
+
+extern char *get_cpu_name(void);
+
+const char *at91_cpu_get_name(void)
+{
+ return get_cpu_name();
+}
+
+int at91_cpu_get_desc(const struct udevice *dev, char *buf, int size)
+{
+ struct at91_cpu_platdata *plat = dev_get_platdata(dev);
+
+ snprintf(buf, size, "%s\n"
+ "Crystal frequency: %8lu MHz\n"
+ "CPU clock : %8lu MHz\n"
+ "Master clock : %8lu MHz\n",
+ plat->name, plat->xtalfreq_mhz, plat->cpufreq_mhz,
+ plat->mckfreq_mhz);
+
+ return 0;
+}
+
+static int at91_cpu_get_info(const struct udevice *dev, struct cpu_info *info)
+{
+ struct at91_cpu_platdata *plat = dev_get_platdata(dev);
+
+ info->cpu_freq = plat->cpufreq_mhz * 1000000;
+ info->features = BIT(CPU_FEAT_L1_CACHE);
+
+ return 0;
+}
+
+static int at91_cpu_get_count(const struct udevice *dev)
+{
+ return 1;
+}
+
+static int at91_cpu_get_vendor(const struct udevice *dev, char *buf, int size)
+{
+ snprintf(buf, size, "Microchip Technology Inc.");
+
+ return 0;
+}
+
+static const struct cpu_ops at91_cpu_ops = {
+ .get_desc = at91_cpu_get_desc,
+ .get_info = at91_cpu_get_info,
+ .get_count = at91_cpu_get_count,
+ .get_vendor = at91_cpu_get_vendor,
+};
+
+static const struct udevice_id at91_cpu_ids[] = {
+ { .compatible = "arm,cortex-a7" },
+ { /* Sentinel. */ }
+};
+
+static int at91_cpu_probe(struct udevice *dev)
+{
+ struct at91_cpu_platdata *plat = dev_get_platdata(dev);
+ struct clk clk;
+ ulong rate;
+ int ret;
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret)
+ return ret;
+
+ rate = clk_get_rate(&clk);
+ if (!rate)
+ return -ENOTSUPP;
+ plat->cpufreq_mhz = DIV_ROUND_CLOSEST_ULL(rate, 1000000);
+
+ ret = clk_get_by_index(dev, 1, &clk);
+ if (ret)
+ return ret;
+
+ rate = clk_get_rate(&clk);
+ if (!rate)
+ return -ENOTSUPP;
+ plat->mckfreq_mhz = DIV_ROUND_CLOSEST_ULL(rate, 1000000);
+
+ ret = clk_get_by_index(dev, 2, &clk);
+ if (ret)
+ return ret;
+
+ rate = clk_get_rate(&clk);
+ if (!rate)
+ return -ENOTSUPP;
+ plat->xtalfreq_mhz = DIV_ROUND_CLOSEST_ULL(rate, 1000000);
+
+ plat->name = get_cpu_name();
+
+ return 0;
+}
+
+U_BOOT_DRIVER(cpu_at91_drv) = {
+ .name = "at91-cpu",
+ .id = UCLASS_CPU,
+ .of_match = at91_cpu_ids,
+ .ops = &at91_cpu_ops,
+ .probe = at91_cpu_probe,
+ .platdata_auto_alloc_size = sizeof(struct at91_cpu_platdata),
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/mmc/atmel_sdhci.c b/drivers/mmc/atmel_sdhci.c
index 0c53caf448c..f56ae63bc2c 100644
--- a/drivers/mmc/atmel_sdhci.c
+++ b/drivers/mmc/atmel_sdhci.c
@@ -79,14 +79,20 @@ static int atmel_sdhci_probe(struct udevice *dev)
if (ret)
return ret;
- ret = clk_set_rate(&clk, ATMEL_SDHC_GCK_RATE);
- if (ret)
- return ret;
+ clk_set_rate(&clk, ATMEL_SDHC_GCK_RATE);
max_clk = clk_get_rate(&clk);
if (!max_clk)
return -EINVAL;
+ ret = clk_enable(&clk);
+ if (ret)
+ return ret;
+
+ ret = mmc_of_parse(dev, &plat->cfg);
+ if (ret)
+ return ret;
+
host->max_clk = max_clk;
host->mmc = &plat->mmc;
host->mmc->dev = dev;
@@ -113,6 +119,7 @@ static int atmel_sdhci_bind(struct udevice *dev)
static const struct udevice_id atmel_sdhci_ids[] = {
{ .compatible = "atmel,sama5d2-sdhci" },
{ .compatible = "microchip,sam9x60-sdhci" },
+ { .compatible = "microchip,sama7g5-sdhci" },
{ }
};
diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c
index fdb7920b558..bf85cc916a7 100644
--- a/drivers/pinctrl/pinctrl-at91-pio4.c
+++ b/drivers/pinctrl/pinctrl-at91-pio4.c
@@ -169,6 +169,7 @@ static int atmel_pinctrl_probe(struct udevice *dev)
static const struct udevice_id atmel_pinctrl_match[] = {
{ .compatible = "atmel,sama5d2-pinctrl" },
+ { .compatible = "microchip,sama7g5-pinctrl" },
{}
};
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index d40d3130113..f8fa4aa71f4 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -213,4 +213,11 @@ config MTK_TIMER
Select this to enable support for the timer found on
MediaTek devices.
+config MCHP_PIT64B_TIMER
+ bool "Microchip 64-bit periodic interval timer support"
+ depends on TIMER
+ help
+ Select this to enable support for Microchip 64-bit periodic
+ interval timer.
+
endmenu
diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile
index c22ffebcdec..3a4d74b996b 100644
--- a/drivers/timer/Makefile
+++ b/drivers/timer/Makefile
@@ -22,3 +22,4 @@ obj-$(CONFIG_STI_TIMER) += sti-timer.o
obj-$(CONFIG_STM32_TIMER) += stm32_timer.o
obj-$(CONFIG_X86_TSC_TIMER) += tsc_timer.o
obj-$(CONFIG_MTK_TIMER) += mtk_timer.o
+obj-$(CONFIG_MCHP_PIT64B_TIMER) += mchp-pit64b-timer.o
diff --git a/drivers/timer/mchp-pit64b-timer.c b/drivers/timer/mchp-pit64b-timer.c
new file mode 100644
index 00000000000..ead8c9b84ad
--- /dev/null
+++ b/drivers/timer/mchp-pit64b-timer.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * 64-bit Periodic Interval Timer driver
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <timer.h>
+#include <asm/io.h>
+
+#define MCHP_PIT64B_CR 0x00 /* Control Register */
+#define MCHP_PIT64B_CR_START BIT(0)
+#define MCHP_PIT64B_CR_SWRST BIT(8)
+#define MCHP_PIT64B_MR 0x04 /* Mode Register */
+#define MCHP_PIT64B_MR_CONT BIT(0)
+#define MCHP_PIT64B_LSB_PR 0x08 /* LSB Period Register */
+#define MCHP_PIT64B_MSB_PR 0x0C /* MSB Period Register */
+#define MCHP_PIT64B_TLSBR 0x20 /* Timer LSB Register */
+#define MCHP_PIT64B_TMSBR 0x24 /* Timer MSB Register */
+
+struct mchp_pit64b_priv {
+ void __iomem *base;
+};
+
+static int mchp_pit64b_get_count(struct udevice *dev, u64 *count)
+{
+ struct mchp_pit64b_priv *priv = dev_get_priv(dev);
+
+ u32 lsb = readl(priv->base + MCHP_PIT64B_TLSBR);
+ u32 msb = readl(priv->base + MCHP_PIT64B_TMSBR);
+
+ *count = ((u64)msb << 32) | lsb;
+
+ return 0;
+}
+
+static int mchp_pit64b_probe(struct udevice *dev)
+{
+ struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct mchp_pit64b_priv *priv = dev_get_priv(dev);
+ struct clk clk;
+ ulong rate;
+ int ret;
+
+ priv->base = dev_read_addr_ptr(dev);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(&clk);
+ if (ret)
+ return ret;
+
+ rate = clk_get_rate(&clk);
+ if (!rate) {
+ clk_disable(&clk);
+ return -ENOTSUPP;
+ }
+
+ /* Reset the timer in case it was used by previous bootloaders. */
+ writel(MCHP_PIT64B_CR_SWRST, priv->base + MCHP_PIT64B_CR);
+
+ /*
+ * Use highest prescaller (for a peripheral clock running at 200MHz
+ * this will lead to the timer running at 12.5MHz) and continuous mode.
+ */
+ writel((15 << 8) | MCHP_PIT64B_MR_CONT, priv->base + MCHP_PIT64B_MR);
+ uc_priv->clock_rate = rate / 16;
+
+ /*
+ * Simulate free running counter by setting max values to period
+ * registers.
+ */
+ writel(~0UL, priv->base + MCHP_PIT64B_MSB_PR);
+ writel(~0UL, priv->base + MCHP_PIT64B_LSB_PR);
+
+ /* Start the timer. */
+ writel(MCHP_PIT64B_CR_START, priv->base + MCHP_PIT64B_CR);
+
+ return 0;
+}
+
+static const struct timer_ops mchp_pit64b_ops = {
+ .get_count = mchp_pit64b_get_count,
+};
+
+static const struct udevice_id mchp_pit64b_ids[] = {
+ { .compatible = "microchip,sam9x60-pit64b", },
+ { .compatible = "microchip,sama7g5-pit64b", },
+ { }
+};
+
+U_BOOT_DRIVER(mchp_pit64b) = {
+ .name = "mchp-pit64b",
+ .id = UCLASS_TIMER,
+ .of_match = mchp_pit64b_ids,
+ .priv_auto_alloc_size = sizeof(struct mchp_pit64b_priv),
+ .probe = mchp_pit64b_probe,
+ .ops = &mchp_pit64b_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h
index 5145fb4e145..1dcc22f6891 100644
--- a/include/dm/device-internal.h
+++ b/include/dm/device-internal.h
@@ -84,6 +84,15 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
struct driver_info *info, struct udevice **devp);
/**
+ * device_reparent: reparent the device to a new parent
+ *
+ * @dev: pointer to device to be reparented
+ * @new_parent: pointer to new parent device
+ * @return 0 if OK, -ve on error
+ */
+int device_reparent(struct udevice *dev, struct udevice *new_parent);
+
+/**
* device_ofdata_to_platdata() - Read platform data for a device
*
* Read platform data for a device (typically from the device tree) so that
diff --git a/include/dt-bindings/clk/at91.h b/include/dt-bindings/clk/at91.h
new file mode 100644
index 00000000000..e30756b2804
--- /dev/null
+++ b/include/dt-bindings/clk/at91.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * This header provides constants for AT91 pmc status.
+ * The constants defined in this header are being used in dts and PMC code.
+ *
+ * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
+ *
+ * Based on include/dt-bindings/clock/at91.h on Linux.
+ */
+
+#ifndef _DT_BINDINGS_CLK_AT91_H
+#define _DT_BINDINGS_CLK_AT91_H
+
+#define PMC_TYPE_CORE 1
+#define PMC_TYPE_SYSTEM 2
+#define PMC_TYPE_PERIPHERAL 3
+#define PMC_TYPE_GCK 4
+#define PMC_TYPE_SLOW 5
+
+#endif
diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h
new file mode 100644
index 00000000000..ee39e72e2b3
--- /dev/null
+++ b/include/linux/clk/at91_pmc.h
@@ -0,0 +1,247 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Power Management Controller (PMC) - System peripherals registers.
+ *
+ * Copyright (C) 2005 Ivan Kokshaysky
+ * Copyright (C) SAN People
+ *
+ * Based on AT91RM9200 datasheet revision E.
+ * Based on include/linux/clk/at91_pmc.h on Linux.
+ */
+
+#ifndef AT91_PMC_H_
+#define AT91_PMC_H_
+
+#define AT91_PMC_V1 (1) /* PMC version 1 */
+#define AT91_PMC_V2 (2) /* PMC version 2 [SAM9X60] */
+
+#define AT91_PMC_SCER 0x00 /* System Clock Enable Register */
+#define AT91_PMC_SCDR 0x04 /* System Clock Disable Register */
+
+#define AT91_PMC_SCSR 0x08 /* System Clock Status Register */
+#define AT91_PMC_PCK (1 << 0) /* Processor Clock */
+#define AT91RM9200_PMC_UDP (1 << 1) /* USB Devcice Port Clock [AT91RM9200 only] */
+#define AT91RM9200_PMC_MCKUDP (1 << 2) /* USB Device Port Master Clock Automatic Disable on Suspend [AT91RM9200 only] */
+#define AT91RM9200_PMC_UHP (1 << 4) /* USB Host Port Clock [AT91RM9200 only] */
+#define AT91SAM926x_PMC_UHP (1 << 6) /* USB Host Port Clock [AT91SAM926x only] */
+#define AT91SAM926x_PMC_UDP (1 << 7) /* USB Devcice Port Clock [AT91SAM926x only] */
+#define AT91_PMC_PCK0 (1 << 8) /* Programmable Clock 0 */
+#define AT91_PMC_PCK1 (1 << 9) /* Programmable Clock 1 */
+#define AT91_PMC_PCK2 (1 << 10) /* Programmable Clock 2 */
+#define AT91_PMC_PCK3 (1 << 11) /* Programmable Clock 3 */
+#define AT91_PMC_PCK4 (1 << 12) /* Programmable Clock 4 [AT572D940HF only] */
+#define AT91_PMC_HCK0 (1 << 16) /* AHB Clock (USB host) [AT91SAM9261 only] */
+#define AT91_PMC_HCK1 (1 << 17) /* AHB Clock (LCD) [AT91SAM9261 only] */
+
+#define AT91_PMC_PLL_CTRL0 0x0C /* PLL Control Register 0 [for SAM9X60] */
+#define AT91_PMC_PLL_CTRL0_ENPLL (1 << 28) /* Enable PLL */
+#define AT91_PMC_PLL_CTRL0_ENPLLCK (1 << 29) /* Enable PLL clock for PMC */
+#define AT91_PMC_PLL_CTRL0_ENLOCK (1 << 31) /* Enable PLL lock */
+
+#define AT91_PMC_PLL_CTRL1 0x10 /* PLL Control Register 1 [for SAM9X60] */
+
+#define AT91_PMC_PCER 0x10 /* Peripheral Clock Enable Register */
+#define AT91_PMC_PCDR 0x14 /* Peripheral Clock Disable Register */
+#define AT91_PMC_PCSR 0x18 /* Peripheral Clock Status Register */
+
+#define AT91_PMC_PLL_ACR 0x18 /* PLL Analog Control Register [for SAM9X60] */
+#define AT91_PMC_PLL_ACR_DEFAULT_UPLL 0x12020010UL /* Default PLL ACR value for UPLL */
+#define AT91_PMC_PLL_ACR_DEFAULT_PLLA 0x00020010UL /* Default PLL ACR value for PLLA */
+#define AT91_PMC_PLL_ACR_UTMIVR (1 << 12) /* UPLL Voltage regulator Control */
+#define AT91_PMC_PLL_ACR_UTMIBG (1 << 13) /* UPLL Bandgap Control */
+
+#define AT91_CKGR_UCKR 0x1C /* UTMI Clock Register [some SAM9] */
+#define AT91_PMC_UPLLEN (1 << 16) /* UTMI PLL Enable */
+#define AT91_PMC_UPLLCOUNT (0xf << 20) /* UTMI PLL Start-up Time */
+#define AT91_PMC_BIASEN (1 << 24) /* UTMI BIAS Enable */
+#define AT91_PMC_BIASCOUNT (0xf << 28) /* UTMI BIAS Start-up Time */
+
+#define AT91_PMC_PLL_UPDT 0x1C /* PMC PLL update register [for SAM9X60] */
+#define AT91_PMC_PLL_UPDT_ID_MSK (0xf)
+#define AT91_PMC_PLL_UPDT_UPDATE (1 << 8) /* Update PLL settings */
+#define AT91_PMC_PLL_UPDT_ID (1 << 0) /* PLL ID */
+#define AT91_PMC_PLL_UPDT_STUPTIM(n) ((n) << 16) /* Startup time */
+#define AT91_PMC_PMM_UPDT_STUPTIM_MSK (0xff << 16)
+
+#define AT91_CKGR_MOR 0x20 /* Main Oscillator Register [not on SAM9RL] */
+#define AT91_PMC_MOSCEN (1 << 0) /* Main Oscillator Enable */
+#define AT91_PMC_OSCBYPASS (1 << 1) /* Oscillator Bypass */
+#define AT91_PMC_WAITMODE (1 << 2) /* Wait Mode Command */
+#define AT91_PMC_MOSCRCEN (1 << 3) /* Main On-Chip RC Oscillator Enable [some SAM9] */
+#define AT91_PMC_OSCOUNT (0xff << 8) /* Main Oscillator Start-up Time */
+#define AT91_PMC_KEY_MASK (0xff << 16)
+#define AT91_PMC_KEY (0x37 << 16) /* MOR Writing Key */
+#define AT91_PMC_MOSCSEL (1 << 24) /* Main Oscillator Selection [some SAM9] */
+#define AT91_PMC_CFDEN (1 << 25) /* Clock Failure Detector Enable [some SAM9] */
+
+#define AT91_CKGR_MCFR 0x24 /* Main Clock Frequency Register */
+#define AT91_PMC_MAINF (0xffff << 0) /* Main Clock Frequency */
+#define AT91_PMC_MAINRDY (1 << 16) /* Main Clock Ready */
+
+#define AT91_CKGR_PLLAR 0x28 /* PLL A Register */
+#define AT91_CKGR_PLLBR 0x2c /* PLL B Register */
+#define AT91_PMC_DIV (0xff << 0) /* Divider */
+#define AT91_PMC_PLLCOUNT (0x3f << 8) /* PLL Counter */
+#define AT91_PMC_OUT (3 << 14) /* PLL Clock Frequency Range */
+#define AT91_PMC_MUL (0x7ff << 16) /* PLL Multiplier */
+#define AT91_PMC_MUL_GET(n) ((n) >> 16 & 0x7ff)
+#define AT91_PMC3_MUL (0x7f << 18) /* PLL Multiplier [SAMA5 only] */
+#define AT91_PMC3_MUL_GET(n) ((n) >> 18 & 0x7f)
+#define AT91_PMC_USBDIV (3 << 28) /* USB Divisor (PLLB only) */
+#define AT91_PMC_USBDIV_1 (0 << 28)
+#define AT91_PMC_USBDIV_2 (1 << 28)
+#define AT91_PMC_USBDIV_4 (2 << 28)
+#define AT91_PMC_USB96M (1 << 28) /* Divider by 2 Enable (PLLB only) */
+
+#define AT91_PMC_CPU_CKR 0x28 /* CPU Clock Register */
+
+#define AT91_PMC_MCKR 0x30 /* Master Clock Register */
+#define AT91_PMC_CSS (3 << 0) /* Master Clock Selection */
+#define AT91_PMC_CSS_SLOW (0 << 0)
+#define AT91_PMC_CSS_MAIN (1 << 0)
+#define AT91_PMC_CSS_PLLA (2 << 0)
+#define AT91_PMC_CSS_PLLB (3 << 0)
+#define AT91_PMC_CSS_UPLL (3 << 0) /* [some SAM9 only] */
+#define PMC_PRES_OFFSET 2
+#define AT91_PMC_PRES (7 << PMC_PRES_OFFSET) /* Master Clock Prescaler */
+#define AT91_PMC_PRES_1 (0 << PMC_PRES_OFFSET)
+#define AT91_PMC_PRES_2 (1 << PMC_PRES_OFFSET)
+#define AT91_PMC_PRES_4 (2 << PMC_PRES_OFFSET)
+#define AT91_PMC_PRES_8 (3 << PMC_PRES_OFFSET)
+#define AT91_PMC_PRES_16 (4 << PMC_PRES_OFFSET)
+#define AT91_PMC_PRES_32 (5 << PMC_PRES_OFFSET)
+#define AT91_PMC_PRES_64 (6 << PMC_PRES_OFFSET)
+#define PMC_ALT_PRES_OFFSET 4
+#define AT91_PMC_ALT_PRES (7 << PMC_ALT_PRES_OFFSET) /* Master Clock Prescaler [alternate location] */
+#define AT91_PMC_ALT_PRES_1 (0 << PMC_ALT_PRES_OFFSET)
+#define AT91_PMC_ALT_PRES_2 (1 << PMC_ALT_PRES_OFFSET)
+#define AT91_PMC_ALT_PRES_4 (2 << PMC_ALT_PRES_OFFSET)
+#define AT91_PMC_ALT_PRES_8 (3 << PMC_ALT_PRES_OFFSET)
+#define AT91_PMC_ALT_PRES_16 (4 << PMC_ALT_PRES_OFFSET)
+#define AT91_PMC_ALT_PRES_32 (5 << PMC_ALT_PRES_OFFSET)
+#define AT91_PMC_ALT_PRES_64 (6 << PMC_ALT_PRES_OFFSET)
+#define AT91_PMC_MDIV (3 << 8) /* Master Clock Division */
+#define AT91RM9200_PMC_MDIV_1 (0 << 8) /* [AT91RM9200 only] */
+#define AT91RM9200_PMC_MDIV_2 (1 << 8)
+#define AT91RM9200_PMC_MDIV_3 (2 << 8)
+#define AT91RM9200_PMC_MDIV_4 (3 << 8)
+#define AT91SAM9_PMC_MDIV_1 (0 << 8) /* [SAM9 only] */
+#define AT91SAM9_PMC_MDIV_2 (1 << 8)
+#define AT91SAM9_PMC_MDIV_4 (2 << 8)
+#define AT91SAM9_PMC_MDIV_6 (3 << 8) /* [some SAM9 only] */
+#define AT91SAM9_PMC_MDIV_3 (3 << 8) /* [some SAM9 only] */
+#define AT91_PMC_PDIV (1 << 12) /* Processor Clock Division [some SAM9 only] */
+#define AT91_PMC_PDIV_1 (0 << 12)
+#define AT91_PMC_PDIV_2 (1 << 12)
+#define AT91_PMC_PLLADIV2 (1 << 12) /* PLLA divisor by 2 [some SAM9 only] */
+#define AT91_PMC_PLLADIV2_OFF (0 << 12)
+#define AT91_PMC_PLLADIV2_ON (1 << 12)
+#define AT91_PMC_H32MXDIV BIT(24)
+
+#define AT91_PMC_XTALF 0x34 /* Main XTAL Frequency Register [SAMA7G5 only] */
+
+#define AT91_PMC_USB 0x38 /* USB Clock Register [some SAM9 only] */
+#define AT91_PMC_USBS (0x1 << 0) /* USB OHCI Input clock selection */
+#define AT91_PMC_USBS_PLLA (0 << 0)
+#define AT91_PMC_USBS_UPLL (1 << 0)
+#define AT91_PMC_USBS_PLLB (1 << 0) /* [AT91SAMN12 only] */
+#define AT91_PMC_OHCIUSBDIV (0xF << 8) /* Divider for USB OHCI Clock */
+#define AT91_PMC_OHCIUSBDIV_1 (0x0 << 8)
+#define AT91_PMC_OHCIUSBDIV_2 (0x1 << 8)
+
+#define AT91_PMC_SMD 0x3c /* Soft Modem Clock Register [some SAM9 only] */
+#define AT91_PMC_SMDS (0x1 << 0) /* SMD input clock selection */
+#define AT91_PMC_SMD_DIV (0x1f << 8) /* SMD input clock divider */
+#define AT91_PMC_SMDDIV(n) (((n) << 8) & AT91_PMC_SMD_DIV)
+
+#define AT91_PMC_PCKR(n) (0x40 + ((n) * 4)) /* Programmable Clock 0-N Registers */
+#define AT91_PMC_ALT_PCKR_CSS (0x7 << 0) /* Programmable Clock Source Selection [alternate length] */
+#define AT91_PMC_CSS_MASTER (4 << 0) /* [some SAM9 only] */
+#define AT91_PMC_CSSMCK (0x1 << 8) /* CSS or Master Clock Selection */
+#define AT91_PMC_CSSMCK_CSS (0 << 8)
+#define AT91_PMC_CSSMCK_MCK (1 << 8)
+
+#define AT91_PMC_IER 0x60 /* Interrupt Enable Register */
+#define AT91_PMC_IDR 0x64 /* Interrupt Disable Register */
+#define AT91_PMC_SR 0x68 /* Status Register */
+#define AT91_PMC_MOSCS (1 << 0) /* MOSCS Flag */
+#define AT91_PMC_LOCKA (1 << 1) /* PLLA Lock */
+#define AT91_PMC_LOCKB (1 << 2) /* PLLB Lock */
+#define AT91_PMC_MCKRDY (1 << 3) /* Master Clock */
+#define AT91_PMC_LOCKU (1 << 6) /* UPLL Lock [some SAM9] */
+#define AT91_PMC_OSCSEL (1 << 7) /* Slow Oscillator Selection [some SAM9] */
+#define AT91_PMC_PCK0RDY (1 << 8) /* Programmable Clock 0 */
+#define AT91_PMC_PCK1RDY (1 << 9) /* Programmable Clock 1 */
+#define AT91_PMC_PCK2RDY (1 << 10) /* Programmable Clock 2 */
+#define AT91_PMC_PCK3RDY (1 << 11) /* Programmable Clock 3 */
+#define AT91_PMC_MOSCSELS (1 << 16) /* Main Oscillator Selection [some SAM9] */
+#define AT91_PMC_MOSCRCS (1 << 17) /* Main On-Chip RC [some SAM9] */
+#define AT91_PMC_CFDEV (1 << 18) /* Clock Failure Detector Event [some SAM9] */
+#define AT91_PMC_GCKRDY (1 << 24) /* Generated Clocks */
+#define AT91_PMC_MCKXRDY (1 << 26) /* Master Clock x [x=1..4] Ready Status */
+#define AT91_PMC_IMR 0x6c /* Interrupt Mask Register */
+
+#define AT91_PMC_FSMR 0x70 /* Fast Startup Mode Register */
+#define AT91_PMC_FSTT(n) BIT(n)
+#define AT91_PMC_RTTAL BIT(16)
+#define AT91_PMC_RTCAL BIT(17) /* RTC Alarm Enable */
+#define AT91_PMC_USBAL BIT(18) /* USB Resume Enable */
+#define AT91_PMC_SDMMC_CD BIT(19) /* SDMMC Card Detect Enable */
+#define AT91_PMC_LPM BIT(20) /* Low-power Mode */
+#define AT91_PMC_RXLP_MCE BIT(24) /* Backup UART Receive Enable */
+#define AT91_PMC_ACC_CE BIT(25) /* ACC Enable */
+
+#define AT91_PMC_FSPR 0x74 /* Fast Startup Polarity Reg */
+
+#define AT91_PMC_FS_INPUT_MASK 0x7ff
+
+#define AT91_PMC_PLLICPR 0x80 /* PLL Charge Pump Current Register */
+
+#define AT91_PMC_PROT 0xe4 /* Write Protect Mode Register [some SAM9] */
+#define AT91_PMC_WPEN (0x1 << 0) /* Write Protect Enable */
+#define AT91_PMC_WPKEY (0xffffff << 8) /* Write Protect Key */
+#define AT91_PMC_PROTKEY (0x504d43 << 8) /* Activation Code */
+
+#define AT91_PMC_WPSR 0xe8 /* Write Protect Status Register [some SAM9] */
+#define AT91_PMC_WPVS (0x1 << 0) /* Write Protect Violation Status */
+#define AT91_PMC_WPVSRC (0xffff << 8) /* Write Protect Violation Source */
+
+#define AT91_PMC_PLL_ISR0 0xEC /* PLL Interrupt Status Register 0 [SAM9X60 only] */
+
+#define AT91_PMC_PCER1 0x100 /* Peripheral Clock Enable Register 1 [SAMA5 only]*/
+#define AT91_PMC_PCDR1 0x104 /* Peripheral Clock Enable Register 1 */
+#define AT91_PMC_PCSR1 0x108 /* Peripheral Clock Enable Register 1 */
+
+#define AT91_PMC_PCR 0x10c /* Peripheral Control Register [some SAM9 and SAMA5] */
+#define AT91_PMC_PCR_PID_MASK 0x3f
+#define AT91_PMC_PCR_CMD (0x1 << 12) /* Command (read=0, write=1) */
+#define AT91_PMC_PCR_GCKDIV_MASK GENMASK(27, 20)
+#define AT91_PMC_PCR_EN (0x1 << 28) /* Enable */
+#define AT91_PMC_PCR_GCKEN (0x1 << 29) /* GCK Enable */
+
+#define AT91_PMC_AUDIO_PLL0 0x14c
+#define AT91_PMC_AUDIO_PLL_PLLEN (1 << 0)
+#define AT91_PMC_AUDIO_PLL_PADEN (1 << 1)
+#define AT91_PMC_AUDIO_PLL_PMCEN (1 << 2)
+#define AT91_PMC_AUDIO_PLL_RESETN (1 << 3)
+#define AT91_PMC_AUDIO_PLL_ND_OFFSET 8
+#define AT91_PMC_AUDIO_PLL_ND_MASK (0x7f << AT91_PMC_AUDIO_PLL_ND_OFFSET)
+#define AT91_PMC_AUDIO_PLL_ND(n) ((n) << AT91_PMC_AUDIO_PLL_ND_OFFSET)
+#define AT91_PMC_AUDIO_PLL_QDPMC_OFFSET 16
+#define AT91_PMC_AUDIO_PLL_QDPMC_MASK (0x7f << AT91_PMC_AUDIO_PLL_QDPMC_OFFSET)
+#define AT91_PMC_AUDIO_PLL_QDPMC(n) ((n) << AT91_PMC_AUDIO_PLL_QDPMC_OFFSET)
+
+#define AT91_PMC_AUDIO_PLL1 0x150
+#define AT91_PMC_AUDIO_PLL_FRACR_MASK 0x3fffff
+#define AT91_PMC_AUDIO_PLL_QDPAD_OFFSET 24
+#define AT91_PMC_AUDIO_PLL_QDPAD_MASK (0x7f << AT91_PMC_AUDIO_PLL_QDPAD_OFFSET)
+#define AT91_PMC_AUDIO_PLL_QDPAD(n) ((n) << AT91_PMC_AUDIO_PLL_QDPAD_OFFSET)
+#define AT91_PMC_AUDIO_PLL_QDPAD_DIV_OFFSET AT91_PMC_AUDIO_PLL_QDPAD_OFFSET
+#define AT91_PMC_AUDIO_PLL_QDPAD_DIV_MASK (0x3 << AT91_PMC_AUDIO_PLL_QDPAD_DIV_OFFSET)
+#define AT91_PMC_AUDIO_PLL_QDPAD_DIV(n) ((n) << AT91_PMC_AUDIO_PLL_QDPAD_DIV_OFFSET)
+#define AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_OFFSET 26
+#define AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_MAX 0x1f
+#define AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_MASK (AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_MAX << AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_OFFSET)
+#define AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV(n) ((n) << AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_OFFSET)
+
+#endif
diff --git a/test/dm/clk_ccf.c b/test/dm/clk_ccf.c
index 32bc4d2b8a0..e4ebb93cdad 100644
--- a/test/dm/clk_ccf.c
+++ b/test/dm/clk_ccf.c
@@ -22,6 +22,10 @@ static int dm_test_clk_ccf(struct unit_test_state *uts)
struct udevice *dev;
long long rate;
int ret;
+#if CONFIG_IS_ENABLED(CLK_CCF)
+ const char *clkname;
+ int clkid, i;
+#endif
/* Get the device using the clk device */
ut_assertok(uclass_get_device_by_name(UCLASS_CLK, "clk-ccf", &dev));
@@ -130,6 +134,59 @@ static int dm_test_clk_ccf(struct unit_test_state *uts)
ret = sandbox_clk_enable_count(pclk);
ut_asserteq(ret, 0);
+
+ /* Test clock re-parenting. */
+ ret = clk_get_by_id(SANDBOX_CLK_USDHC1_SEL, &clk);
+ ut_assertok(ret);
+ ut_asserteq_str("usdhc1_sel", clk->dev->name);
+
+ pclk = clk_get_parent(clk);
+ ut_assertok_ptr(pclk);
+ if (!strcmp(pclk->dev->name, "pll3_60m")) {
+ clkname = "pll3_80m";
+ clkid = SANDBOX_CLK_PLL3_80M;
+ } else {
+ clkname = "pll3_60m";
+ clkid = SANDBOX_CLK_PLL3_60M;
+ }
+
+ ret = clk_get_by_id(clkid, &pclk);
+ ut_assertok(ret);
+ ret = clk_set_parent(clk, pclk);
+ ut_assertok(ret);
+ pclk = clk_get_parent(clk);
+ ut_assertok_ptr(pclk);
+ ut_asserteq_str(clkname, pclk->dev->name);
+
+ /* Test disabling critical clock. */
+ ret = clk_get_by_id(SANDBOX_CLK_I2C_ROOT, &clk);
+ ut_assertok(ret);
+ ut_asserteq_str("i2c_root", clk->dev->name);
+
+ /* Disable it, if any. */
+ ret = sandbox_clk_enable_count(clk);
+ for (i = 0; i < ret; i++) {
+ ret = clk_disable(clk);
+ ut_assertok(ret);
+ }
+
+ ret = sandbox_clk_enable_count(clk);
+ ut_asserteq(ret, 0);
+
+ clk->flags = CLK_IS_CRITICAL;
+ ret = clk_enable(clk);
+ ut_assertok(ret);
+
+ ret = clk_disable(clk);
+ ut_assertok(ret);
+ ret = sandbox_clk_enable_count(clk);
+ ut_asserteq(ret, 1);
+ clk->flags &= ~CLK_IS_CRITICAL;
+
+ ret = clk_disable(clk);
+ ut_assertok(ret);
+ ret = sandbox_clk_enable_count(clk);
+ ut_asserteq(ret, 0);
#endif
return 1;
diff --git a/test/dm/core.c b/test/dm/core.c
index 8ed5bf73705..6f380a574cf 100644
--- a/test/dm/core.c
+++ b/test/dm/core.c
@@ -643,6 +643,166 @@ static int dm_test_children(struct unit_test_state *uts)
}
DM_TEST(dm_test_children, 0);
+static int dm_test_device_reparent(struct unit_test_state *uts)
+{
+ struct dm_test_state *dms = uts->priv;
+ struct udevice *top[NODE_COUNT];
+ struct udevice *child[NODE_COUNT];
+ struct udevice *grandchild[NODE_COUNT];
+ struct udevice *dev;
+ int total;
+ int ret;
+ int i;
+
+ /* We don't care about the numbering for this test */
+ dms->skip_post_probe = 1;
+
+ ut_assert(NODE_COUNT > 5);
+
+ /* First create 10 top-level children */
+ ut_assertok(create_children(uts, dms->root, NODE_COUNT, 0, top));
+
+ /* Now a few have their own children */
+ ut_assertok(create_children(uts, top[2], NODE_COUNT, 2, NULL));
+ ut_assertok(create_children(uts, top[5], NODE_COUNT, 5, child));
+
+ /* And grandchildren */
+ for (i = 0; i < NODE_COUNT; i++)
+ ut_assertok(create_children(uts, child[i], NODE_COUNT, 50 * i,
+ i == 2 ? grandchild : NULL));
+
+ /* Check total number of devices */
+ total = NODE_COUNT * (3 + NODE_COUNT);
+ ut_asserteq(total, dm_testdrv_op_count[DM_TEST_OP_BIND]);
+
+ /* Probe everything */
+ for (i = 0; i < total; i++)
+ ut_assertok(uclass_get_device(UCLASS_TEST, i, &dev));
+
+ /* Re-parent top-level children with no grandchildren. */
+ ut_assertok(device_reparent(top[3], top[0]));
+ /* try to get devices */
+ for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
+ dev;
+ ret = uclass_find_next_device(&dev)) {
+ ut_assert(!ret);
+ ut_assertnonnull(dev);
+ }
+
+ ut_assertok(device_reparent(top[4], top[0]));
+ /* try to get devices */
+ for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
+ dev;
+ ret = uclass_find_next_device(&dev)) {
+ ut_assert(!ret);
+ ut_assertnonnull(dev);
+ }
+
+ /* Re-parent top-level children with grandchildren. */
+ ut_assertok(device_reparent(top[2], top[0]));
+ /* try to get devices */
+ for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
+ dev;
+ ret = uclass_find_next_device(&dev)) {
+ ut_assert(!ret);
+ ut_assertnonnull(dev);
+ }
+
+ ut_assertok(device_reparent(top[5], top[2]));
+ /* try to get devices */
+ for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
+ dev;
+ ret = uclass_find_next_device(&dev)) {
+ ut_assert(!ret);
+ ut_assertnonnull(dev);
+ }
+
+ /* Re-parent grandchildren. */
+ ut_assertok(device_reparent(grandchild[0], top[1]));
+ /* try to get devices */
+ for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
+ dev;
+ ret = uclass_find_next_device(&dev)) {
+ ut_assert(!ret);
+ ut_assertnonnull(dev);
+ }
+
+ ut_assertok(device_reparent(grandchild[1], top[1]));
+ /* try to get devices */
+ for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
+ dev;
+ ret = uclass_find_next_device(&dev)) {
+ ut_assert(!ret);
+ ut_assertnonnull(dev);
+ }
+
+ /* Remove re-pareneted devices. */
+ ut_assertok(device_remove(top[3], DM_REMOVE_NORMAL));
+ /* try to get devices */
+ for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
+ dev;
+ ret = uclass_find_next_device(&dev)) {
+ ut_assert(!ret);
+ ut_assertnonnull(dev);
+ }
+
+ ut_assertok(device_remove(top[4], DM_REMOVE_NORMAL));
+ /* try to get devices */
+ for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
+ dev;
+ ret = uclass_find_next_device(&dev)) {
+ ut_assert(!ret);
+ ut_assertnonnull(dev);
+ }
+
+ ut_assertok(device_remove(top[5], DM_REMOVE_NORMAL));
+ /* try to get devices */
+ for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
+ dev;
+ ret = uclass_find_next_device(&dev)) {
+ ut_assert(!ret);
+ ut_assertnonnull(dev);
+ }
+
+ ut_assertok(device_remove(top[2], DM_REMOVE_NORMAL));
+ for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
+ dev;
+ ret = uclass_find_next_device(&dev)) {
+ ut_assert(!ret);
+ ut_assertnonnull(dev);
+ }
+
+ ut_assertok(device_remove(grandchild[0], DM_REMOVE_NORMAL));
+ /* try to get devices */
+ for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
+ dev;
+ ret = uclass_find_next_device(&dev)) {
+ ut_assert(!ret);
+ ut_assertnonnull(dev);
+ }
+
+ ut_assertok(device_remove(grandchild[1], DM_REMOVE_NORMAL));
+ /* try to get devices */
+ for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
+ dev;
+ ret = uclass_find_next_device(&dev)) {
+ ut_assert(!ret);
+ ut_assertnonnull(dev);
+ }
+
+ /* Try the same with unbind */
+ ut_assertok(device_unbind(top[3]));
+ ut_assertok(device_unbind(top[4]));
+ ut_assertok(device_unbind(top[5]));
+ ut_assertok(device_unbind(top[2]));
+
+ ut_assertok(device_unbind(grandchild[0]));
+ ut_assertok(device_unbind(grandchild[1]));
+
+ return 0;
+}
+DM_TEST(dm_test_device_reparent, 0);
+
/* Test that pre-relocation devices work as expected */
static int dm_test_pre_reloc(struct unit_test_state *uts)
{