summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2020-10-05 10:54:27 -0400
committerTom Rini <trini@konsulko.com>2020-10-05 10:54:27 -0400
commitcaebff09efe8c061b4d99b82262c67fb2db9bbcf (patch)
tree24fcdb0737bea1d87c0a36f7eb371017af83e5c2
parent17e76b33cc0ec2eb2c519b66b6f6c491718e8046 (diff)
parent01c35f269f21398fa9d1db1b90b73f7e95a3bf22 (diff)
downloadu-boot-WIP/05Oct2020-next.tar.gz
Merge tag 'u-boot-atmel-2021.01-a' of https://gitlab.denx.de/u-boot/custodians/u-boot-atmel into nextWIP/05Oct2020-next
First set of u-boot-atmel features for 2021.01 cycle: This feature set includes a new CPU driver for at91 family, new driver for PIT64B hardware timer, support for new at91 family SoC named sama7g5 which adds: clock support, including conversion of the clock tree to CCF; SoC support in mach-at91, pinctrl and mmc drivers update. The feature set also includes updates for mmc driver and some other minor fixes and features regarding building without the old Atmel PIT and the possibility to read a secondary MAC address from a second i2c EEPROM.
-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 c96b8b6baa..85babd1908 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 0000000000..89293e5470
--- /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 85524004f9..be1415f909 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 9ced3dc0c1..55477560a8 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 a8f4356ce9..8b7355042b 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 0000000000..a58f671f72
--- /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 01e00c508a..f7b411cf7d 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 88acca8549..0a16c8ff08 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 0000000000..ae43e8700b
--- /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 2205dd30f8..a723ba723c 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 8d482a2752..4abc8026b4 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 8c197ff949..2453c38af1 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 c0610940c3..0000000000
--- 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 0000000000..87738b7b5b
--- /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 86bb71f612..0000000000
--- 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 b31a1cb682..b52d926f33 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 e078fab7b4..759df93697 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 cd9d5e77c0..52cbc520ce 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 79d725819f..0000000000
--- 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 ca6158ef6a..0000000000
--- 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 0000000000..868de4b177
--- /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 0000000000..1bfae5fd01
--- /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 1f8665768b..0000000000
--- 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 76b1958670..82f79e74a1 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 af9d724369..0000000000
--- 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 18af0bfeaa..7c8bcfb51d 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 0000000000..8cf6254046
--- /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 ca90abef2d..660e231921 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 517ba1d6b4..a6a714fd22 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 0000000000..b96937673b
--- /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 a879b008ff..dd62dc5510 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 934cd5787a..4076535271 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 786f4e887e..319808d433 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 355dbd147a..e90d70101c 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 0b5dbc7c88..c8532637ca 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 0000000000..058ae3a811
--- /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 0c53caf448..f56ae63bc2 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 fdb7920b55..bf85cc916a 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 d40d313011..f8fa4aa71f 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 c22ffebcde..3a4d74b996 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 0000000000..ead8c9b84a
--- /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 5145fb4e14..1dcc22f689 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 0000000000..e30756b280
--- /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 0000000000..ee39e72e2b
--- /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 32bc4d2b8a..e4ebb93cda 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 8ed5bf7370..6f380a574c 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)
{