diff --git a/boards/microchip/sam/sama7d65_curiosity/Kconfig.sama7d65_curiosity b/boards/microchip/sam/sama7d65_curiosity/Kconfig.sama7d65_curiosity new file mode 100644 index 0000000000000..5556c4d81b09f --- /dev/null +++ b/boards/microchip/sam/sama7d65_curiosity/Kconfig.sama7d65_curiosity @@ -0,0 +1,7 @@ +# Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries +# +# SPDX-License-Identifier: Apache-2.0 +# + +config BOARD_SAMA7D65_CURIOSITY + select SOC_SAMA7D65 diff --git a/boards/microchip/sam/sama7d65_curiosity/board.yml b/boards/microchip/sam/sama7d65_curiosity/board.yml new file mode 100644 index 0000000000000..324e86c23c1c3 --- /dev/null +++ b/boards/microchip/sam/sama7d65_curiosity/board.yml @@ -0,0 +1,6 @@ +board: + name: sama7d65_curiosity + full_name: SAMA7D65 Curiosity Kit + vendor: microchip + socs: + - name: sama7d65 diff --git a/boards/microchip/sam/sama7d65_curiosity/doc/img/sama7d65_curiosity.webp b/boards/microchip/sam/sama7d65_curiosity/doc/img/sama7d65_curiosity.webp new file mode 100644 index 0000000000000..a0d44e8e3a850 Binary files /dev/null and b/boards/microchip/sam/sama7d65_curiosity/doc/img/sama7d65_curiosity.webp differ diff --git a/boards/microchip/sam/sama7d65_curiosity/doc/index.rst b/boards/microchip/sam/sama7d65_curiosity/doc/index.rst new file mode 100644 index 0000000000000..f374b1f2fdd99 --- /dev/null +++ b/boards/microchip/sam/sama7d65_curiosity/doc/index.rst @@ -0,0 +1,109 @@ +.. zephyr:board:: sama7d65_curiosity + +Overview +******** + +The EV63J76A (SAMA7D65 Curiosity Kit) is a development kit for evaluating and +prototyping with Microchip SAMA7D65 microprocessor (MPU). The SAMA7D65 MPU is a +high-performance ARM Cortex-A7 CPU-based embedded MPU running up to 1GHz. + +The board allows evaluation of powerful peripherals for connectivity, audio and +user interface applications, including MIPI-DSI and LVDS w/ 2D graphics, dual +Gigabit Ethernet w/ TSN and CAN-FD. The MPUs offer advanced security functions, +like tamper detection, secure boot, secure key stoarge, TRNG, PUF as well as +higher-performance crypto accelerators for AES and SHA. + +The SAMA7D65 series is supported by Microchip MPLAB-X development tools, Harmony +V3, Linux distributions and Microchip Graphic Suite (MGS) for Linux. The +SAMA7D65 is well-suited for industrial and automotive applications with +graphical displays support up to WXGA/720p. + +Hardware +******** +EV63J76A provides the following hardware components: + +- Processor + + - Microchip SAMA7D65-V/4HB (SoC 343-ball TFBGA, 14x14 mm, 0.65 mm pitch) + +- Memory + + - 8 Gb DDR3L (AS4C512M16D3LA-10BIN) + - 64 Mb QSPI NOR Flash with EUI-48 (Microchip SST26VF064BEUI-104I/MF) + - 4Gbit SLC NAND Flash (MX30LF4G28AD-XKI) + - 2Kb EEPROM with EUI-48 (Microchip 24AA025E48) + +- SD/MMC + + - One SD card socket, 4 bit + - One M.2 Radio Module interface, SDIO I/F + +- USB + + - One device USB Type-C connector + - Two host USB Type-A connectors (Microchip MIC2026-1YM) + +- Ethernet + + - One 10/100/1000 RGMII on board + - One 10/100/1000 RGMII SODIMM add-on slot (Microchip LAN8840-V/PSA) + +- Display + + - One MIPI-DSI 34-pin FPC connector + - One LVDS 30-pin FPC connector + +- Debug port + + - One UART Debug connector + - One JTAG interface + +- User interaction + + - One RGB (Red, Green, Blue) LED + - Four push button switches + +- CAN-FD + + - Three onboard CAN-FD transceivers + - Two interfaces available on mikroBUS slots + +- Expansion + + - Raspberry Pi 40-pin GPIO connector + - Two mikroBUS™ connectors + - Two PIOBU/System headers + +- Power management + + - Power Supply Unit (Microchip MCP16502TAB-E/S8B) + - Power Monitoring (Microchip PAC1934) + - Daughter cards power supply (Microchip MIC23450-AAAYML-TR) + - Backup power supply (CR1220 battery holder) + +- Board supply + + - System 5 VDC from USB Type-C + - System 5 VDC from DC Jack + +Supported Features +================== + +.. zephyr:board-supported-hw:: + +Connections and IOs +=================== + +The `SAMA7D65-Curiosity Kit User Guide`_ has detailed information about board connections. + +References +********** + +SAMA7D65 Product Page: + https://www.microchip.com/en-us/product/sama7d65 + +SAMA7D65 Curiosity Kit Page: + https://www.microchip.com/en-us/development-tool/EV63J76A + +.. _SAMA7D65-Curiosity Kit User Guide: + https://ww1.microchip.com/downloads/aemDocuments/documents/MPU32/ProductDocuments/UserGuides/SAMA7D65-Curiosity-Kit-User-Guide-DS50003806.pdf diff --git a/boards/microchip/sam/sama7d65_curiosity/sama7d65_curiosity.dts b/boards/microchip/sam/sama7d65_curiosity/sama7d65_curiosity.dts new file mode 100644 index 0000000000000..36e6a911441b6 --- /dev/null +++ b/boards/microchip/sam/sama7d65_curiosity/sama7d65_curiosity.dts @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +/dts-v1/; +#include +#include +#include +#include + +/ { + model = "SAMA7D65-Curiosity board"; + compatible = "microchip,sama7d65curiosity", "microchip,sama7d6", "microchip,sama7"; + + chosen { + zephyr,sram = &ddram; + zephyr,console = &uart6; + zephyr,shell-uart = &uart6; + }; + + clocks { + main_xtal { + clock-frequency = ; + }; + + slow_xtal { + clock-frequency = <32768>; + }; + }; + + ddram: ddram@60000000 { + compatible = "ddram"; + reg = <0x60000000 DT_SIZE_M(1024)>; + }; +}; + +&flx6 { + mchp,flexcom-mode = ; + status = "okay"; + + uart6: serial@200 { + current-speed = <115200>; + pinctrl-0 = <&pinctrl_uart6_default>; + pinctrl-names = "default"; + status = "okay"; + }; +}; + +&pinctrl { + pinctrl_uart6_default: uart6-default { + group1 { + pinmux = , + ; + bias-disable; + }; + }; +}; + +&pit64b0 { + clock-frequency = ; +}; diff --git a/boards/microchip/sam/sama7d65_curiosity/sama7d65_curiosity.yaml b/boards/microchip/sam/sama7d65_curiosity/sama7d65_curiosity.yaml new file mode 100644 index 0000000000000..c8a1692f0e19c --- /dev/null +++ b/boards/microchip/sam/sama7d65_curiosity/sama7d65_curiosity.yaml @@ -0,0 +1,14 @@ +# Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries +# SPDX-License-Identifier: Apache-2.0 + +identifier: sama7d65_curiosity +name: SAMA7D65 Curiosity Kit +type: mcu +arch: arm +toolchain: + - zephyr +ram: 128 +supported: + - shell + - uart +vendor: microchip diff --git a/boards/microchip/sam/sama7d65_curiosity/sama7d65_curiosity_defconfig b/boards/microchip/sam/sama7d65_curiosity/sama7d65_curiosity_defconfig new file mode 100644 index 0000000000000..10b06d0f7f423 --- /dev/null +++ b/boards/microchip/sam/sama7d65_curiosity/sama7d65_curiosity_defconfig @@ -0,0 +1,9 @@ +# Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_CLOCK_CONTROL_FIXED_RATE_CLOCK=y +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y diff --git a/dts/arm/microchip/sam/sama7d65.dtsi b/dts/arm/microchip/sam/sama7d65.dtsi new file mode 100644 index 0000000000000..a8de93d5151c8 --- /dev/null +++ b/dts/arm/microchip/sam/sama7d65.dtsi @@ -0,0 +1,421 @@ +/* + * Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include +#include +#include +#include +#include + +/ { + model = "Microchip SAMA7D65 family SoC"; + compatible = "microchip,sama7d6"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0>; + }; + }; + + clocks { + main_xtal: main_xtal { + compatible = "fixed-clock"; + #clock-cells = <0>; + }; + + slow_xtal: slow_xtal { + compatible = "fixed-clock"; + #clock-cells = <0>; + }; + }; + + soc { + clk32k: clock-controller@e001d500 { + compatible = "microchip,sama7g5-sckc", "microchip,sam9x60-sckc"; + reg = <0xe001d500 0x4>; + clocks = <&slow_xtal>; + #clock-cells = <1>; + }; + + flx0: flexcom@e1820000 { + compatible = "microchip,sam-flexcom"; + reg = <0xe1820000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xe1820000 0x800>; + status = "disabled"; + + i2c0: i2c0@600 { + compatible = "atmel,sam-i2c-twi"; + reg = <0x600 0x200>; + clock-frequency = ; + interrupt-parent = <&gic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 34>; + status = "disabled"; + }; + + uart0: serial@200 { + compatible = "atmel,sam-usart"; + reg = <0x200 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 34>; + interrupt-parent = <&gic>; + interrupts = ; + status = "disabled"; + }; + }; + + flx1: flexcom@e1824000 { + compatible = "microchip,sam-flexcom"; + reg = <0xe1824000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xe1824000 0x800>; + status = "disabled"; + + i2c1: i2c1@600 { + compatible = "atmel,sam-i2c-twi"; + reg = <0x600 0x200>; + clock-frequency = ; + interrupt-parent = <&gic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 35>; + status = "disabled"; + }; + + uart1: serial@200 { + compatible = "atmel,sam-usart"; + reg = <0x200 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 35>; + interrupt-parent = <&gic>; + interrupts = ; + status = "disabled"; + }; + }; + + flx2: flexcom@e1828000 { + compatible = "microchip,sam-flexcom"; + reg = <0xe1828000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xe1828000 0x800>; + status = "disabled"; + + i2c2: i2c2@600 { + compatible = "atmel,sam-i2c-twi"; + reg = <0x600 0x200>; + clock-frequency = ; + interrupt-parent = <&gic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 36>; + status = "disabled"; + }; + + uart2: serial@200 { + compatible = "atmel,sam-usart"; + reg = <0x200 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 36>; + interrupt-parent = <&gic>; + interrupts = ; + status = "disabled"; + }; + }; + + flx3: flexcom@e182c000 { + compatible = "microchip,sam-flexcom"; + reg = <0xe182c000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xe182c000 0x800>; + status = "disabled"; + + i2c3: i2c3@600 { + compatible = "atmel,sam-i2c-twi"; + reg = <0x600 0x200>; + clock-frequency = ; + interrupt-parent = <&gic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 37>; + status = "disabled"; + }; + + uart3: serial@200 { + compatible = "atmel,sam-usart"; + reg = <0x200 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 37>; + interrupt-parent = <&gic>; + interrupts = ; + status = "disabled"; + }; + }; + + flx4: flexcom@e2018000 { + compatible = "microchip,sam-flexcom"; + reg = <0xe2018000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xe2018000 0x800>; + status = "disabled"; + + i2c4: i2c4@600 { + compatible = "atmel,sam-i2c-twi"; + reg = <0x600 0x200>; + clock-frequency = ; + interrupt-parent = <&gic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 38>; + status = "disabled"; + }; + + uart4: serial@200 { + compatible = "atmel,sam-usart"; + reg = <0x200 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 38>; + interrupt-parent = <&gic>; + interrupts = ; + status = "disabled"; + }; + }; + + flx5: flexcom@e201c000 { + compatible = "microchip,sam-flexcom"; + reg = <0xe201c000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xe201c000 0x800>; + status = "disabled"; + + i2c5: i2c5@600 { + compatible = "atmel,sam-i2c-twi"; + reg = <0x600 0x200>; + clock-frequency = ; + interrupt-parent = <&gic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 39>; + status = "disabled"; + }; + + uart5: serial@200 { + compatible = "atmel,sam-usart"; + reg = <0x200 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 39>; + interrupt-parent = <&gic>; + interrupts = ; + status = "disabled"; + }; + }; + + flx6: flexcom@e2020000 { + compatible = "microchip,sam-flexcom"; + reg = <0xe2020000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xe2020000 0x800>; + status = "disabled"; + + i2c6: i2c6@600 { + compatible = "atmel,sam-i2c-twi"; + reg = <0x600 0x200>; + clock-frequency = ; + interrupt-parent = <&gic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 40>; + status = "disabled"; + }; + + uart6: serial@200 { + compatible = "atmel,sam-usart"; + reg = <0x200 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 40>; + interrupt-parent = <&gic>; + interrupts = ; + status = "disabled"; + }; + }; + + flx7: flexcom@e2024000 { + compatible = "microchip,sam-flexcom"; + reg = <0xe2024000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xe2024000 0x800>; + status = "disabled"; + + i2c7: i2c7@600 { + compatible = "atmel,sam-i2c-twi"; + reg = <0x600 0x200>; + clock-frequency = ; + interrupt-parent = <&gic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 41>; + status = "disabled"; + }; + + uart7: serial@200 { + compatible = "atmel,sam-usart"; + reg = <0x200 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 41>; + interrupt-parent = <&gic>; + interrupts = ; + status = "disabled"; + }; + }; + + flx8: flexcom@e281c000 { + compatible = "microchip,sam-flexcom"; + reg = <0xe281c000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xe281c000 0x800>; + status = "disabled"; + + i2c8: i2c8@600 { + compatible = "atmel,sam-i2c-twi"; + reg = <0x600 0x200>; + clock-frequency = ; + interrupt-parent = <&gic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 42>; + status = "disabled"; + }; + + uart8: serial@200 { + compatible = "atmel,sam-usart"; + reg = <0x200 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 42>; + interrupt-parent = <&gic>; + interrupts = ; + status = "disabled"; + }; + }; + + flx9: flexcom@e2820000 { + compatible = "microchip,sam-flexcom"; + reg = <0xe2820000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xe2820000 0x800>; + status = "disabled"; + + i2c9: i2c9@600 { + compatible = "atmel,sam-i2c-twi"; + reg = <0x600 0x200>; + clock-frequency = ; + interrupt-parent = <&gic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 43>; + status = "disabled"; + }; + + uart9: serial@200 { + compatible = "atmel,sam-usart"; + reg = <0x200 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 43>; + interrupt-parent = <&gic>; + interrupts = ; + status = "disabled"; + }; + }; + + flx10: flexcom@e2824000 { + compatible = "microchip,sam-flexcom"; + reg = <0xe2824000 0x200>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xe2824000 0x800>; + status = "disabled"; + + i2c10: i2c10@600 { + compatible = "atmel,sam-i2c-twi"; + reg = <0x600 0x200>; + clock-frequency = ; + interrupt-parent = <&gic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 44>; + status = "disabled"; + }; + + uart10: serial@200 { + compatible = "atmel,sam-usart"; + reg = <0x200 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 44>; + interrupt-parent = <&gic>; + interrupts = ; + status = "disabled"; + }; + }; + + gic: interrupt-controller@e8c11000 { + compatible = "arm,gic-v2", "arm,gic"; + reg = <0xe8c11000 0x1000>, <0xe8c12000 0x100>; + interrupt-controller; + #interrupt-cells = <4>; + }; + + rtc: rtc@e001d800 { + compatible = "atmel,sam-rtc"; + reg = <0xe001d800 0x30>; + interrupt-parent = <&gic>; + interrupts = ; + clocks = <&clk32k 1>; + }; + + sram: memory@100000 { + compatible = "mmio-sram"; + reg = <0x00100000 DT_SIZE_K(128)>; + }; + + pinctrl: pinctrl@e0014000 { + compatible = "microchip,sama7g5-pinctrl"; + reg = <0xe0014000 0x800>; + }; + + pit64b0: timer@e1800000 { + compatible = "microchip,sam-pit64b", "microchip,sam9x60-pit64b"; + reg = <0xe1800000 0x4000>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 66>, <&pmc PMC_TYPE_GCK 66>; + clock-names = "pclk", "gclk"; + interrupt-parent = <&gic>; + interrupts = ; + }; + + pmc: clock-controller@e0018000 { + compatible = "microchip,sam-pmc"; + reg = <0xe0018000 0x200>; + #clock-cells = <2>; + clocks = <&clk32k 1>, <&clk32k 0>, <&main_xtal>; + clock-names = "td_slck", "md_slck", "main_xtal"; + }; + }; +}; diff --git a/include/zephyr/dt-bindings/clock/microchip_sam_pmc.h b/include/zephyr/dt-bindings/clock/microchip_sam_pmc.h index 0656f3de97162..a2e2fa94051df 100644 --- a/include/zephyr/dt-bindings/clock/microchip_sam_pmc.h +++ b/include/zephyr/dt-bindings/clock/microchip_sam_pmc.h @@ -33,4 +33,9 @@ #define UTMI2 1 #define UTMI3 2 +/* SAMA7D65 */ +#define PMC_LVDSPLL (PMC_MAIN + 12) +#define PMC_MCK3 (PMC_MAIN + 20) +#define PMC_MCK5 (PMC_MAIN + 21) + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_MICROCHIP_SAM_PMC_H_ */ diff --git a/soc/microchip/sam/Kconfig b/soc/microchip/sam/Kconfig index 2f5bd7b320dfc..67a7dbef40237 100644 --- a/soc/microchip/sam/Kconfig +++ b/soc/microchip/sam/Kconfig @@ -3,6 +3,11 @@ # SPDX-License-Identifier: Apache-2.0 # +config SOC_SERIES_SAMA7D6 + select ARM + select CPU_CORTEX_A7 + select SOC_EARLY_INIT_HOOK + config SOC_SERIES_SAMA7G5 select ARM select CPU_CORTEX_A7 diff --git a/soc/microchip/sam/common/CMakeLists.txt b/soc/microchip/sam/common/CMakeLists.txt index bbb4727fdf383..50d11f5d75504 100644 --- a/soc/microchip/sam/common/CMakeLists.txt +++ b/soc/microchip/sam/common/CMakeLists.txt @@ -12,6 +12,7 @@ zephyr_sources(clk-peripheral.c) zephyr_sources(clk-programmable.c) zephyr_sources(clk-sam9x60-pll.c) zephyr_sources(clk-system.c) -zephyr_sources(clk-utmi.c) +zephyr_sources_ifdef(CONFIG_SOC_SERIES_SAMA7G5 clk-utmi.c) zephyr_sources(pmc.c) +zephyr_sources_ifdef(CONFIG_SOC_SERIES_SAMA7D6 sama7d65.c) zephyr_sources_ifdef(CONFIG_SOC_SERIES_SAMA7G5 sama7g5.c) diff --git a/soc/microchip/sam/common/clk-generated.c b/soc/microchip/sam/common/clk-generated.c index e8452cc6bd6e4..4c6c5ae201046 100644 --- a/soc/microchip/sam/common/clk-generated.c +++ b/soc/microchip/sam/common/clk-generated.c @@ -29,7 +29,7 @@ struct clk_generated { #define to_clk_generated(ptr) CONTAINER_OF(ptr, struct clk_generated, clk) -static struct clk_generated clocks_gck[ID_PERIPH_MAX]; +static struct clk_generated clocks_gck[SOC_NUM_CLOCK_GENERATED]; static uint32_t clocks_gck_idx; static int clk_generated_on(const struct device *dev, clock_control_subsys_t sys) diff --git a/soc/microchip/sam/common/clk-master.c b/soc/microchip/sam/common/clk-master.c index f721ea466a03b..a56099a4e97eb 100644 --- a/soc/microchip/sam/common/clk-master.c +++ b/soc/microchip/sam/common/clk-master.c @@ -19,7 +19,7 @@ LOG_MODULE_REGISTER(clk_mck, CONFIG_CLOCK_CONTROL_LOG_LEVEL); #define PMC_MCR_CSS_SHIFT 16 -#define MASTER_MAX_ID 4 +#define MASTER_MAX_ID (SOC_NUM_CLOCK_MASTER - 1) #define to_clk_master(ptr) CONTAINER_OF(ptr, struct clk_master, clk) @@ -38,7 +38,7 @@ struct clk_master { uint8_t div; }; -static struct clk_master clocks_master[5]; +static struct clk_master clocks_master[SOC_NUM_CLOCK_MASTER]; static uint32_t clocks_master_idx; static inline bool clk_master_ready(struct clk_master *master) diff --git a/soc/microchip/sam/common/clk-peripheral.c b/soc/microchip/sam/common/clk-peripheral.c index 2fdc1117d340f..094c37d613c69 100644 --- a/soc/microchip/sam/common/clk-peripheral.c +++ b/soc/microchip/sam/common/clk-peripheral.c @@ -25,7 +25,7 @@ struct clk_peripheral { const struct clk_pcr_layout *layout; }; -static struct clk_peripheral clocks_periph[72]; +static struct clk_peripheral clocks_periph[SOC_NUM_CLOCK_PERIPHERAL]; static uint32_t clocks_periph_idx; #define to_clk_peripheral(ptr) CONTAINER_OF(ptr, struct clk_peripheral, clk) diff --git a/soc/microchip/sam/common/clk-programmable.c b/soc/microchip/sam/common/clk-programmable.c index fb17512c2e1a6..bbac3badb4c0a 100644 --- a/soc/microchip/sam/common/clk-programmable.c +++ b/soc/microchip/sam/common/clk-programmable.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include #include @@ -25,6 +26,7 @@ struct clk_programmable { uint8_t num_parents; uint8_t parent; const struct clk_programmable_layout *layout; + char name[8]; }; #define to_clk_programmable(ptr) CONTAINER_OF(ptr, struct clk_programmable, clk) @@ -79,7 +81,7 @@ static DEVICE_API(clock_control, programmable_api) = { .get_rate = clk_programmable_get_rate, }; -int clk_register_programmable(pmc_registers_t *const pmc, const char *name, +int clk_register_programmable(pmc_registers_t *const pmc, const struct device **parents, uint8_t num_parents, uint8_t id, const struct clk_programmable_layout *layout, @@ -102,9 +104,10 @@ int clk_register_programmable(pmc_registers_t *const pmc, const char *name, } memcpy(prog->parents, parents, sizeof(struct device *) * num_parents); + snprintf(prog->name, sizeof(prog->name), "prog%d", id); *clk = &prog->clk; - (*clk)->name = name; + (*clk)->name = prog->name; (*clk)->api = &programmable_api; prog->num_parents = num_parents; prog->id = id; diff --git a/soc/microchip/sam/common/clk-sam9x60-pll.c b/soc/microchip/sam/common/clk-sam9x60-pll.c index 0a3a00d50a792..bd3d65d100200 100644 --- a/soc/microchip/sam/common/clk-sam9x60-pll.c +++ b/soc/microchip/sam/common/clk-sam9x60-pll.c @@ -46,7 +46,7 @@ LOG_MODULE_REGISTER(clk_pll, CONFIG_CLOCK_CONTROL_LOG_LEVEL); q * n_ + r * n_ / d_; \ }) -#define PLL_MAX_ID 7 +#define PLL_MAX_ID SOC_NUM_CLOCK_PLL_FRAC struct sam9x60_pll_core { pmc_registers_t *pmc; @@ -73,10 +73,10 @@ struct sam9x60_div { #define to_sam9x60_frac(ptr) CONTAINER_OF(ptr, struct sam9x60_frac, core) #define to_sam9x60_div(ptr) CONTAINER_OF(ptr, struct sam9x60_div, core) -static struct sam9x60_frac clocks_frac[7]; +static struct sam9x60_frac clocks_frac[SOC_NUM_CLOCK_PLL_FRAC]; static uint32_t clocks_frac_idx; -static struct sam9x60_div clocks_div[8]; +static struct sam9x60_div clocks_div[SOC_NUM_CLOCK_PLL_DIV]; static uint32_t clocks_div_idx; static inline bool sam9x60_pll_ready(pmc_registers_t *pmc, int id) diff --git a/soc/microchip/sam/common/clk-system.c b/soc/microchip/sam/common/clk-system.c index 453408a31935c..d300a8ce66a7d 100644 --- a/soc/microchip/sam/common/clk-system.c +++ b/soc/microchip/sam/common/clk-system.c @@ -25,7 +25,7 @@ struct clk_system { uint8_t id; }; -static struct clk_system clocks_sys[8]; +static struct clk_system clocks_sys[SOC_NUM_CLOCK_SYSTEM]; static uint32_t clocks_sys_idx; static inline int is_pck(int id) diff --git a/soc/microchip/sam/common/pmc.h b/soc/microchip/sam/common/pmc.h index a46238f509ed1..72112c5185d30 100644 --- a/soc/microchip/sam/common/pmc.h +++ b/soc/microchip/sam/common/pmc.h @@ -68,6 +68,7 @@ struct clk_pll_characteristics { uint16_t *icpll; uint8_t *out; uint8_t upll : 1; + uint32_t acr; }; struct clk_programmable_layout { @@ -168,7 +169,7 @@ int sam9x60_clk_register_frac_pll(pmc_registers_t *const pmc, struct k_spinlock const struct clk_pll_characteristics *characteristics, const struct clk_pll_layout *layout, struct device **clk); -int clk_register_programmable(pmc_registers_t *const pmc, const char *name, +int clk_register_programmable(pmc_registers_t *const pmc, const struct device **parents, uint8_t num_parents, uint8_t id, const struct clk_programmable_layout *layout, diff --git a/soc/microchip/sam/common/sama7d65.c b/soc/microchip/sam/common/sama7d65.c new file mode 100644 index 0000000000000..094f836752958 --- /dev/null +++ b/soc/microchip/sam/common/sama7d65.c @@ -0,0 +1,1382 @@ +/* + * Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(pmc_setup, CONFIG_CLOCK_CONTROL_LOG_LEVEL); + +#define nck(a) (a[ARRAY_SIZE(a) - 1].id + 1) + +#define SAMA7D65_INIT_TABLE(_table, _count) \ + do { \ + uint8_t _i; \ + for (_i = 0; _i < (_count); _i++) { \ + (_table)[_i] = _i; \ + } \ + } while (0) + +#define SAMA7D65_FILL_TABLE(_to, _from, _count) \ + do { \ + uint8_t _i; \ + for (_i = 0; _i < (_count); _i++) { \ + (_to)[_i] = (_from)[_i]; \ + } \ + } while (0) + +static struct k_spinlock pmc_pll_lock; +static struct k_spinlock pmc_mck0_lock; +static struct k_spinlock pmc_mckX_lock; +static struct k_spinlock pmc_pcr_lock; + +/* + * PLL clocks identifiers + * @PLL_ID_CPU: CPU PLL identifier + * @PLL_ID_SYS: System PLL identifier + * @PLL_ID_DDR: DDR PLL identifier + * @PLL_ID_IMG: Image subsystem PLL identifier + * @PLL_ID_BAUD: Baud PLL identifier + * @PLL_ID_AUDIO: Audio PLL identifier + * @PLL_ID_ETH: Ethernet PLL identifier + * @PLL_ID_LVDS: LVDS PLL identifier + * @PLL_ID_USB: USB PLL identifier + */ +enum pll_ids { + PLL_ID_CPU, + PLL_ID_SYS, + PLL_ID_DDR, + PLL_ID_GPU, + PLL_ID_BAUD, + PLL_ID_AUDIO, + PLL_ID_ETH, + PLL_ID_LVDS, + PLL_ID_USB, + PLL_ID_MAX, +}; + +/* + * PLL component identifier + * @PLL_COMPID_FRAC: Fractional PLL component identifier + * @PLL_COMPID_DIV0: 1st PLL divider component identifier + * @PLL_COMPID_DIV1: 2nd PLL divider component identifier + */ +enum pll_component_id { + PLL_COMPID_FRAC, + PLL_COMPID_DIV0, + PLL_COMPID_DIV1, +}; + +/* + * PLL type identifiers + * @PLL_TYPE_FRAC: fractional PLL identifier + * @PLL_TYPE_DIV: divider PLL identifier + */ +enum pll_type { + PLL_TYPE_FRAC, + PLL_TYPE_DIV, +}; + +/* Layout for fractional PLLs. */ +static const struct clk_pll_layout pll_layout_frac = { + .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, +}; + +/* + * CPU PLL output range. + * Notice: The upper limit has been setup to 1000000002 due to hardware + * block which cannot output exactly 1GHz. + */ +static const struct clk_range cpu_pll_outputs[] = { + { .min = 2343750, .max = 1000000002 }, +}; + +/* PLL output range. */ +static const struct clk_range pll_outputs[] = { + { .min = 2343750, .max = 1200000000 }, +}; + +/* + * Min: fCOREPLLCK = 600 MHz, PMC_PLL_CTRL0.DIVPMC = 255 + * Max: fCOREPLLCK = 800 MHz, PMC_PLL_CTRL0.DIVPMC = 0 + */ +static const struct clk_range lvdspll_outputs[] = { + { .min = 16406250, .max = 800000000 }, +}; + +static const struct clk_range upll_outputs[] = { + { .min = 480000000, .max = 480000000 }, +}; + +/* Fractional PLL core output range. */ +static const struct clk_range core_outputs[] = { + { .min = 600000000, .max = 1200000000 }, +}; + +static const struct clk_range lvdspll_core_outputs[] = { + { .min = 600000000, .max = 1200000000 }, +}; + +static const struct clk_range upll_core_outputs[] = { + { .min = 600000000, .max = 1200000000 }, +}; + +/* CPU PLL characteristics. */ +static const struct clk_pll_characteristics cpu_pll_characteristics = { + .input = { .min = 12000000, .max = 50000000 }, + .num_output = ARRAY_SIZE(cpu_pll_outputs), + .output = cpu_pll_outputs, + .core_output = core_outputs, + .acr = 0x00070010, +}; + +/* PLL characteristics. */ +static const struct clk_pll_characteristics pll_characteristics = { + .input = { .min = 12000000, .max = 50000000 }, + .num_output = ARRAY_SIZE(pll_outputs), + .output = pll_outputs, + .core_output = core_outputs, + .acr = 0x00070010, +}; + +static const struct clk_pll_characteristics lvdspll_characteristics = { + .input = { .min = 12000000, .max = 50000000 }, + .num_output = ARRAY_SIZE(lvdspll_outputs), + .output = lvdspll_outputs, + .core_output = lvdspll_core_outputs, + .acr = 0x00070010, +}; + +static const struct clk_pll_characteristics upll_characteristics = { + .input = { .min = 20000000, .max = 50000000 }, + .num_output = ARRAY_SIZE(upll_outputs), + .output = upll_outputs, + .core_output = upll_core_outputs, + .acr = 0x12020010, + .upll = true, +}; + +/* + * SAMA7D65 PLL possible parents + * @SAMA7D65_PLL_PARENT_MAINCK: MAINCK is PLL a parent + * @SAMA7D65_PLL_PARENT_MAIN_XTAL: MAIN XTAL is a PLL parent + * @SAMA7D65_PLL_PARENT_FRACCK: Frac PLL is a PLL parent (for PLL dividers) + */ +enum sama7d65_pll_parent { + SAMA7D65_PLL_PARENT_MAINCK, + SAMA7D65_PLL_PARENT_MAIN_XTAL, + SAMA7D65_PLL_PARENT_FRACCK, +}; + +/* + * PLL clocks description + * @n: clock name + * @p: clock parent + * @l: clock layout + * @c: clock characteristics + * @hw: pointer to clk_hw + * @t: clock type + * @f: clock flags + * @p: clock parent + * @eid: export index in sama7d65->chws[] array + * @safe_div: intermediate divider need to be set on PRE_RATE_CHANGE + * notification + */ +static struct sama7d65_pll { + const char *n; + const struct clk_pll_layout *l; + const struct clk_pll_characteristics *c; + struct device *clk; + unsigned long f; + enum sama7d65_pll_parent p; + uint8_t t; + uint8_t eid; + uint8_t safe_div; +} sama7d65_plls[][PLL_ID_MAX] = { + [PLL_ID_CPU] = { + [PLL_COMPID_FRAC] = { + .n = "cpupll_fracck", + .p = SAMA7D65_PLL_PARENT_MAINCK, + .l = &pll_layout_frac, + .c = &cpu_pll_characteristics, + .t = PLL_TYPE_FRAC, + }, + + [PLL_COMPID_DIV0] = { + .n = "cpupll_divpmcck", + .p = SAMA7D65_PLL_PARENT_FRACCK, + .l = &pll_layout_divpmc, + .c = &cpu_pll_characteristics, + .t = PLL_TYPE_DIV, + .eid = PMC_CPUPLL, + /* + * Safe div=15 should be safe even for switching b/w 1GHz and + * 90MHz (frac pll might go up to 1.2GHz). + */ + .safe_div = 15, + }, + }, + + [PLL_ID_SYS] = { + [PLL_COMPID_FRAC] = { + .n = "syspll_fracck", + .p = SAMA7D65_PLL_PARENT_MAINCK, + .l = &pll_layout_frac, + .c = &pll_characteristics, + .t = PLL_TYPE_FRAC, + }, + + [PLL_COMPID_DIV0] = { + .n = "syspll_divpmcck", + .p = SAMA7D65_PLL_PARENT_FRACCK, + .l = &pll_layout_divpmc, + .c = &pll_characteristics, + .t = PLL_TYPE_DIV, + .eid = PMC_SYSPLL, + }, + }, + + [PLL_ID_DDR] = { + [PLL_COMPID_FRAC] = { + .n = "ddrpll_fracck", + .p = SAMA7D65_PLL_PARENT_MAINCK, + .l = &pll_layout_frac, + .c = &pll_characteristics, + .t = PLL_TYPE_FRAC, + }, + + [PLL_COMPID_DIV0] = { + .n = "ddrpll_divpmcck", + .p = SAMA7D65_PLL_PARENT_FRACCK, + .l = &pll_layout_divpmc, + .c = &pll_characteristics, + .t = PLL_TYPE_DIV, + }, + }, + + [PLL_ID_GPU] = { + [PLL_COMPID_FRAC] = { + .n = "gpupll_fracck", + .p = SAMA7D65_PLL_PARENT_MAINCK, + .l = &pll_layout_frac, + .c = &pll_characteristics, + .t = PLL_TYPE_FRAC, + }, + + [PLL_COMPID_DIV0] = { + .n = "gpupll_divpmcck", + .p = SAMA7D65_PLL_PARENT_FRACCK, + .l = &pll_layout_divpmc, + .c = &pll_characteristics, + .t = PLL_TYPE_DIV, + }, + }, + + [PLL_ID_BAUD] = { + [PLL_COMPID_FRAC] = { + .n = "baudpll_fracck", + .p = SAMA7D65_PLL_PARENT_MAINCK, + .l = &pll_layout_frac, + .c = &pll_characteristics, + .t = PLL_TYPE_FRAC, + }, + + [PLL_COMPID_DIV0] = { + .n = "baudpll_divpmcck", + .p = SAMA7D65_PLL_PARENT_FRACCK, + .l = &pll_layout_divpmc, + .c = &pll_characteristics, + .t = PLL_TYPE_DIV, + .eid = PMC_BAUDPLL, + }, + }, + + [PLL_ID_AUDIO] = { + [PLL_COMPID_FRAC] = { + .n = "audiopll_fracck", + .p = SAMA7D65_PLL_PARENT_MAIN_XTAL, + .l = &pll_layout_frac, + .c = &pll_characteristics, + .t = PLL_TYPE_FRAC, + }, + + [PLL_COMPID_DIV0] = { + .n = "audiopll_divpmcck", + .p = SAMA7D65_PLL_PARENT_FRACCK, + .l = &pll_layout_divpmc, + .c = &pll_characteristics, + .t = PLL_TYPE_DIV, + .eid = PMC_AUDIOPMCPLL, + }, + + [PLL_COMPID_DIV1] = { + .n = "audiopll_diviock", + .p = SAMA7D65_PLL_PARENT_FRACCK, + .l = &pll_layout_divio, + .c = &pll_characteristics, + .t = PLL_TYPE_DIV, + .eid = PMC_AUDIOIOPLL, + }, + }, + + [PLL_ID_ETH] = { + [PLL_COMPID_FRAC] = { + .n = "ethpll_fracck", + .p = SAMA7D65_PLL_PARENT_MAIN_XTAL, + .l = &pll_layout_frac, + .c = &pll_characteristics, + .t = PLL_TYPE_FRAC, + }, + + [PLL_COMPID_DIV0] = { + .n = "ethpll_divpmcck", + .p = SAMA7D65_PLL_PARENT_FRACCK, + .l = &pll_layout_divpmc, + .c = &pll_characteristics, + .t = PLL_TYPE_DIV, + .eid = PMC_ETHPLL, + }, + }, + + [PLL_ID_LVDS] = { + [PLL_COMPID_FRAC] = { + .n = "lvdspll_fracck", + .p = SAMA7D65_PLL_PARENT_MAIN_XTAL, + .l = &pll_layout_frac, + .c = &lvdspll_characteristics, + .t = PLL_TYPE_FRAC, + }, + + [PLL_COMPID_DIV0] = { + .n = "lvdspll_divpmcck", + .p = SAMA7D65_PLL_PARENT_FRACCK, + .l = &pll_layout_divpmc, + .c = &lvdspll_characteristics, + .t = PLL_TYPE_DIV, + .eid = PMC_LVDSPLL, + }, + }, + + [PLL_ID_USB] = { + [PLL_COMPID_FRAC] = { + .n = "usbpll_fracck", + .p = SAMA7D65_PLL_PARENT_MAIN_XTAL, + .l = &pll_layout_frac, + .c = &upll_characteristics, + .t = PLL_TYPE_FRAC, + }, + + [PLL_COMPID_DIV0] = { + .n = "usbpll_divpmcck", + .p = SAMA7D65_PLL_PARENT_FRACCK, + .l = &pll_layout_divpmc, + .c = &upll_characteristics, + .t = PLL_TYPE_DIV, + .eid = PMC_UTMI, + }, + }, +}; + +/* Used to create an array entry identifying a PLL by its components. */ +#define PLL_IDS_TO_ARR_ENTRY(_id, _comp) { PLL_ID_##_id, PLL_COMPID_##_comp} + +/* + * Master clock (MCK[1..4]) description + * @n: clock name + * @ep_chg_chg_id: index in parents array that specifies the changeable + * @ep: extra parents names array (entry formed by PLL components + * identifiers (see enum pll_component_id)) + * @hw: pointer to clk_hw + * parent + * @ep_count: extra parents count + * @ep_mux_table: mux table for extra parents + * @id: clock id + * @eid: export index in sama7d65->chws[] array + * @c: true if clock is critical and cannot be disabled + */ +static struct { + const char *n; + struct { + int pll_id; + int pll_compid; + } ep[4]; + struct device *clk; + int ep_chg_id; + uint8_t ep_count; + uint8_t ep_mux_table[4]; + uint8_t id; + uint8_t eid; + uint8_t c; +} sama7d65_mckx[] = { + { .n = "mck0", }, /* Dummy entry for MCK0 to store hw in probe. */ + { .n = "mck1", + .id = 1, + .ep = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .ep_mux_table = { 5, }, + .ep_count = 1, + .ep_chg_id = INT_MIN, + .eid = PMC_MCK1, + .c = 1, }, + + { .n = "mck2", + .id = 2, + .ep = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(DDR, DIV0), }, + .ep_mux_table = { 5, 6, }, + .ep_count = 2, + .ep_chg_id = INT_MIN, + .c = 1, }, + + { .n = "mck3", + .id = 3, + .ep = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(DDR, DIV0), }, + .ep_mux_table = { 5, 6, }, + .ep_count = 2, + .ep_chg_id = INT_MIN, + .eid = PMC_MCK3, + .c = 1, }, + + { .n = "mck4", + .id = 4, + .ep = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .ep_mux_table = { 5, }, + .ep_count = 1, + .ep_chg_id = INT_MIN, + .c = 1,}, + + { .n = "mck5", + .id = 5, + .ep = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .ep_mux_table = { 5, }, + .ep_count = 1, + .ep_chg_id = INT_MIN, + .eid = PMC_MCK5, + .c = 1,}, + + { .n = "mck6", + .id = 6, + .ep = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .ep_mux_table = { 5, }, + .ep_chg_id = INT_MIN, + .ep_count = 1, + .c = 1,}, + + { .n = "mck7", + .id = 7, + .ep = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .ep_mux_table = { 5, }, + .ep_chg_id = INT_MIN, + .ep_count = 1,}, + + { .n = "mck8", + .id = 8, + .ep = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .ep_mux_table = { 5, }, + .ep_chg_id = INT_MIN, + .ep_count = 1,}, + + { .n = "mck9", + .id = 9, + .ep = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .ep_mux_table = { 5, }, + .ep_chg_id = INT_MIN, + .ep_count = 1, }, +}; + +/* + * System clock description + * @n: clock name + * @p: clock parent name + * @id: clock id + */ +static const struct { + const char *n; + const char *p; + uint8_t id; +} sama7d65_systemck[] = { + { .n = "pck0", .p = "prog0", .id = 8, }, + { .n = "pck1", .p = "prog1", .id = 9, }, + { .n = "pck2", .p = "prog2", .id = 10, }, + { .n = "pck3", .p = "prog3", .id = 11, }, + { .n = "pck4", .p = "prog4", .id = 12, }, + { .n = "pck5", .p = "prog5", .id = 13, }, + { .n = "pck6", .p = "prog6", .id = 14, }, + { .n = "pck7", .p = "prog7", .id = 15, }, +}; + +/* Mux table for programmable clocks. */ +static uint32_t sama7d65_prog_mux_table[] = { 0, 1, 2, 5, 7, 8, 9, 10, 12,}; + +/* + * Peripheral clock parent hw identifier (used to index in sama7d65_mckx[]) + * @PCK_PARENT_HW_MCK0: pck parent hw identifier is MCK0 + * @PCK_PARENT_HW_MCK1: pck parent hw identifier is MCK1 + * @PCK_PARENT_HW_MCK2: pck parent hw identifier is MCK2 + * @PCK_PARENT_HW_MCK3: pck parent hw identifier is MCK3 + * @PCK_PARENT_HW_MCK4: pck parent hw identifier is MCK4 + * @PCK_PARENT_HW_MCK5: pck parent hw identifier is MCK5 + * @PCK_PARENT_HW_MCK6: pck parent hw identifier is MCK6 + * @PCK_PARENT_HW_MCK7: pck parent hw identifier is MCK7 + * @PCK_PARENT_HW_MCK8: pck parent hw identifier is MCK8 + * @PCK_PARENT_HW_MCK9: pck parent hw identifier is MCK9 + * @PCK_PARENT_HW_MAX: max identifier + */ +enum sama7d65_pck_parent_hw_id { + PCK_PARENT_HW_MCK0, + PCK_PARENT_HW_MCK1, + PCK_PARENT_HW_MCK2, + PCK_PARENT_HW_MCK3, + PCK_PARENT_HW_MCK4, + PCK_PARENT_HW_MCK5, + PCK_PARENT_HW_MCK6, + PCK_PARENT_HW_MCK7, + PCK_PARENT_HW_MCK8, + PCK_PARENT_HW_MCK9, + PCK_PARENT_HW_MAX, +}; + +/* + * Peripheral clock description + * @n: clock name + * @p: clock parent hw id + * @r: clock range values + * @id: clock id + * @chgp: index in parent array of the changeable parent + */ +static struct { + const char *n; + enum sama7d65_pck_parent_hw_id p; + struct clk_range r; + uint8_t chgp; + uint8_t id; +} sama7d65_periphck[] = { + { .n = "pioA_clk", .p = PCK_PARENT_HW_MCK0, .id = 10, }, + { .n = "securam_clk", .p = PCK_PARENT_HW_MCK0, .id = 17, }, + { .n = "sfr_clk", .p = PCK_PARENT_HW_MCK7, .id = 18, }, + { .n = "hsmc_clk", .p = PCK_PARENT_HW_MCK5, .id = 20, }, + { .n = "xdmac0_clk", .p = PCK_PARENT_HW_MCK6, .id = 21, }, + { .n = "xdmac1_clk", .p = PCK_PARENT_HW_MCK6, .id = 22, }, + { .n = "xdmac2_clk", .p = PCK_PARENT_HW_MCK1, .id = 23, }, + { .n = "acc_clk", .p = PCK_PARENT_HW_MCK7, .id = 24, }, + { .n = "aes_clk", .p = PCK_PARENT_HW_MCK6, .id = 26, }, + { .n = "tzaesbasc_clk", .p = PCK_PARENT_HW_MCK8, .id = 27, }, + { .n = "asrc_clk", .p = PCK_PARENT_HW_MCK9, .id = 29, .r = { .max = 200000000, }, }, + { .n = "cpkcc_clk", .p = PCK_PARENT_HW_MCK0, .id = 30, }, + { .n = "eic_clk", .p = PCK_PARENT_HW_MCK7, .id = 33, }, + { .n = "flex0_clk", .p = PCK_PARENT_HW_MCK7, .id = 34, }, + { .n = "flex1_clk", .p = PCK_PARENT_HW_MCK7, .id = 35, }, + { .n = "flex2_clk", .p = PCK_PARENT_HW_MCK7, .id = 36, }, + { .n = "flex3_clk", .p = PCK_PARENT_HW_MCK7, .id = 37, }, + { .n = "flex4_clk", .p = PCK_PARENT_HW_MCK8, .id = 38, }, + { .n = "flex5_clk", .p = PCK_PARENT_HW_MCK8, .id = 39, }, + { .n = "flex6_clk", .p = PCK_PARENT_HW_MCK8, .id = 40, }, + { .n = "flex7_clk", .p = PCK_PARENT_HW_MCK8, .id = 41, }, + { .n = "flex8_clk", .p = PCK_PARENT_HW_MCK9, .id = 42, }, + { .n = "flex9_clk", .p = PCK_PARENT_HW_MCK9, .id = 43, }, + { .n = "flex10_clk", .p = PCK_PARENT_HW_MCK9, .id = 44, }, + { .n = "gmac0_clk", .p = PCK_PARENT_HW_MCK6, .id = 46, }, + { .n = "gmac1_clk", .p = PCK_PARENT_HW_MCK6, .id = 47, }, + { .n = "gmac0_tsu_clk", .p = PCK_PARENT_HW_MCK1, .id = 49, }, + { .n = "gmac1_tsu_clk", .p = PCK_PARENT_HW_MCK1, .id = 50, }, + { .n = "icm_clk", .p = PCK_PARENT_HW_MCK5, .id = 53, }, + { .n = "i2smcc0_clk", .p = PCK_PARENT_HW_MCK9, .id = 54, .r = { .max = 200000000, }, }, + { .n = "i2smcc1_clk", .p = PCK_PARENT_HW_MCK9, .id = 55, .r = { .max = 200000000, }, }, + { .n = "lcd_clk", .p = PCK_PARENT_HW_MCK3, .id = 56, }, + { .n = "matrix_clk", .p = PCK_PARENT_HW_MCK5, .id = 57, }, + { .n = "mcan0_clk", .p = PCK_PARENT_HW_MCK5, .id = 58, .r = { .max = 200000000, }, }, + { .n = "mcan1_clk", .p = PCK_PARENT_HW_MCK5, .id = 59, .r = { .max = 200000000, }, }, + { .n = "mcan2_clk", .p = PCK_PARENT_HW_MCK5, .id = 60, .r = { .max = 200000000, }, }, + { .n = "mcan3_clk", .p = PCK_PARENT_HW_MCK5, .id = 61, .r = { .max = 200000000, }, }, + { .n = "mcan4_clk", .p = PCK_PARENT_HW_MCK5, .id = 62, .r = { .max = 200000000, }, }, + { .n = "pdmc0_clk", .p = PCK_PARENT_HW_MCK9, .id = 64, .r = { .max = 200000000, }, }, + { .n = "pdmc1_clk", .p = PCK_PARENT_HW_MCK9, .id = 65, .r = { .max = 200000000, }, }, + { .n = "pit64b0_clk", .p = PCK_PARENT_HW_MCK7, .id = 66, }, + { .n = "pit64b1_clk", .p = PCK_PARENT_HW_MCK7, .id = 67, }, + { .n = "pit64b2_clk", .p = PCK_PARENT_HW_MCK7, .id = 68, }, + { .n = "pit64b3_clk", .p = PCK_PARENT_HW_MCK8, .id = 69, }, + { .n = "pit64b4_clk", .p = PCK_PARENT_HW_MCK8, .id = 70, }, + { .n = "pit64b5_clk", .p = PCK_PARENT_HW_MCK8, .id = 71, }, + { .n = "pwm_clk", .p = PCK_PARENT_HW_MCK7, .id = 72, }, + { .n = "qspi0_clk", .p = PCK_PARENT_HW_MCK5, .id = 73, }, + { .n = "qspi1_clk", .p = PCK_PARENT_HW_MCK5, .id = 74, }, + { .n = "sdmmc0_clk", .p = PCK_PARENT_HW_MCK1, .id = 75, }, + { .n = "sdmmc1_clk", .p = PCK_PARENT_HW_MCK1, .id = 76, }, + { .n = "sdmmc2_clk", .p = PCK_PARENT_HW_MCK1, .id = 77, }, + { .n = "sha_clk", .p = PCK_PARENT_HW_MCK6, .id = 78, }, + { .n = "spdifrx_clk", .p = PCK_PARENT_HW_MCK9, .id = 79, .r = { .max = 200000000, }, }, + { .n = "spdiftx_clk", .p = PCK_PARENT_HW_MCK9, .id = 80, .r = { .max = 200000000, }, }, + { .n = "ssc0_clk", .p = PCK_PARENT_HW_MCK7, .id = 81, .r = { .max = 200000000, }, }, + { .n = "ssc1_clk", .p = PCK_PARENT_HW_MCK8, .id = 82, .r = { .max = 200000000, }, }, + { .n = "tcb0_ch0_clk", .p = PCK_PARENT_HW_MCK8, .id = 83, .r = { .max = 200000000, }, }, + { .n = "tcb0_ch1_clk", .p = PCK_PARENT_HW_MCK8, .id = 84, .r = { .max = 200000000, }, }, + { .n = "tcb0_ch2_clk", .p = PCK_PARENT_HW_MCK8, .id = 85, .r = { .max = 200000000, }, }, + { .n = "tcb1_ch0_clk", .p = PCK_PARENT_HW_MCK5, .id = 86, .r = { .max = 200000000, }, }, + { .n = "tcb1_ch1_clk", .p = PCK_PARENT_HW_MCK5, .id = 87, .r = { .max = 200000000, }, }, + { .n = "tcb1_ch2_clk", .p = PCK_PARENT_HW_MCK5, .id = 88, .r = { .max = 200000000, }, }, + { .n = "tcpca_clk", .p = PCK_PARENT_HW_MCK5, .id = 89, }, + { .n = "tcpcb_clk", .p = PCK_PARENT_HW_MCK5, .id = 90, }, + { .n = "tdes_clk", .p = PCK_PARENT_HW_MCK6, .id = 91, }, + { .n = "trng_clk", .p = PCK_PARENT_HW_MCK6, .id = 92, }, + { .n = "udphsa_clk", .p = PCK_PARENT_HW_MCK5, .id = 99, }, + { .n = "udphsb_clk", .p = PCK_PARENT_HW_MCK5, .id = 100, }, + { .n = "uhphs_clk", .p = PCK_PARENT_HW_MCK5, .id = 101, }, + { .n = "dsi_clk", .p = PCK_PARENT_HW_MCK3, .id = 103, }, + { .n = "lvdsc_clk", .p = PCK_PARENT_HW_MCK3, .id = 104, }, +}; + +/* + * Generic clock description + * @n: clock name + * @pp: PLL parents (entry formed by PLL components identifiers + * (see enum pll_component_id)) + * @pp_mux_table: PLL parents mux table + * @r: clock output range + * @pp_chg_id: id in parent array of changeable PLL parent + * @pp_count: PLL parents count + * @id: clock id + */ +static const struct { + const char *n; + struct { + int pll_id; + int pll_compid; + } pp[8]; + const char pp_mux_table[8]; + struct clk_range r; + int pp_chg_id; + uint8_t pp_count; + uint8_t id; +} sama7d65_gck[] = { + { .n = "adc_gclk", + .id = 25, + .r = { .max = 100000000, }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), }, + .pp_mux_table = { 8, 9, }, + .pp_count = 2, + .pp_chg_id = INT_MIN, }, + + { .n = "asrc_gclk", + .id = 29, + .r = { .max = 200000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), }, + .pp_mux_table = { 9, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "flex0_gclk", + .id = 34, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = {8, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "flex1_gclk", + .id = 35, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = {8, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "flex2_gclk", + .id = 36, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = {8, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "flex3_gclk", + .id = 37, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = {8, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "flex4_gclk", + .id = 38, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = { 8, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "flex5_gclk", + .id = 39, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = { 8, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "flex6_gclk", + .id = 40, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = { 8, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "flex7_gclk", + .id = 41, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = { 8, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "flex8_gclk", + .id = 42, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = { 8, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "flex9_gclk", + .id = 43, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = { 8, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "flex10_gclk", + .id = 44, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = { 8, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "gmac0_gclk", + .id = 46, + .r = { .max = 125000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = { 10, }, + .pp_count = 1, + .pp_chg_id = 4, }, + + { .n = "gmac1_gclk", + .id = 47, + .r = { .max = 125000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = { 10, }, + .pp_count = 1, + .pp_chg_id = 4, }, + + { .n = "gmac0_tsu_gclk", + .id = 49, + .r = { .max = 400000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = {10, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "gmac1_tsu_gclk", + .id = 50, + .r = { .max = 400000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = { 10, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "i2smcc0_gclk", + .id = 54, + .r = { .max = 100000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), }, + .pp_mux_table = { 9, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "i2smcc1_gclk", + .id = 55, + .r = { .max = 100000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), }, + .pp_mux_table = { 9, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "lcdc_gclk", + .id = 56, + .r = { .max = 90000000 }, + .pp_count = 0, + .pp_chg_id = INT_MIN, + }, + + { .n = "mcan0_gclk", + .id = 58, + .r = { .max = 80000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(USB, DIV0), }, + .pp_mux_table = { 12 }, + .pp_count = 1, + .pp_chg_id = 4, }, + + { .n = "mcan1_gclk", + .id = 59, + .r = { .max = 80000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(USB, DIV0), }, + .pp_mux_table = { 12 }, + .pp_count = 1, + .pp_chg_id = 4, }, + + { .n = "mcan2_gclk", + .id = 60, + .r = { .max = 80000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(USB, DIV0), }, + .pp_mux_table = { 12 }, + .pp_count = 1, + .pp_chg_id = 4, }, + + { .n = "mcan3_gclk", + .id = 61, + .r = { .max = 80000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(USB, DIV0), }, + .pp_mux_table = { 12 }, + .pp_count = 1, + .pp_chg_id = 4, }, + + { .n = "mcan4_gclk", + .id = 62, + .r = { .max = 80000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(USB, DIV0), }, + .pp_mux_table = { 12 }, + .pp_count = 1, + .pp_chg_id = 4, }, + + { .n = "pdmc0_gclk", + .id = 64, + .r = { .max = 80000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), }, + .pp_mux_table = { 9 }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "pdmc1_gclk", + .id = 65, + .r = { .max = 80000000, }, + .pp = { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), }, + .pp_mux_table = { 9, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "pit64b0_gclk", + .id = 66, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = { 8, 9, 10, }, + .pp_count = 3, + .pp_chg_id = INT_MIN, }, + + { .n = "pit64b1_gclk", + .id = 67, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = { 8, 9, 10, }, + .pp_count = 3, + .pp_chg_id = INT_MIN, }, + + { .n = "pit64b2_gclk", + .id = 68, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = { 8, 9, 10, }, + .pp_count = 3, + .pp_chg_id = INT_MIN, }, + + { .n = "pit64b3_gclk", + .id = 69, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = {8, 9, 10, }, + .pp_count = 3, + .pp_chg_id = INT_MIN, }, + + { .n = "pit64b4_gclk", + .id = 70, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = {8, 9, 10, }, + .pp_count = 3, + .pp_chg_id = INT_MIN, }, + + { .n = "pit64b5_gclk", + .id = 71, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = {8, 9, 10, }, + .pp_count = 3, + .pp_chg_id = INT_MIN, }, + + { .n = "qspi0_gclk", + .id = 73, + .r = { .max = 400000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = { 5, 8, }, + .pp_count = 2, + .pp_chg_id = INT_MIN, }, + + { .n = "qspi1_gclk", + .id = 74, + .r = { .max = 266000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), }, + .pp_mux_table = { 5, 8, }, + .pp_count = 2, + .pp_chg_id = INT_MIN, }, + + { .n = "sdmmc0_gclk", + .id = 75, + .r = { .max = 208000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = { 8, 10, }, + .pp_count = 2, + .pp_chg_id = 4, }, + + { .n = "sdmmc1_gclk", + .id = 76, + .r = { .max = 208000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = { 8, 10, }, + .pp_count = 2, + .pp_chg_id = 4, }, + + { .n = "sdmmc2_gclk", + .id = 77, + .r = { .max = 208000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = { 8, 10 }, + .pp_count = 2, + .pp_chg_id = 4, }, + + { .n = "spdifrx_gclk", + .id = 79, + .r = { .max = 150000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), }, + .pp_mux_table = { 9, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "spdiftx_gclk", + .id = 80, + .r = { .max = 25000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), }, + .pp_mux_table = { 9, }, + .pp_count = 1, + .pp_chg_id = INT_MIN, }, + + { .n = "tcb0_ch0_gclk", + .id = 83, + .r = { .max = 34000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = { 8, 9, 10, }, + .pp_count = 3, + .pp_chg_id = INT_MIN, }, + + { .n = "tcb1_ch0_gclk", + .id = 86, + .r = { .max = 67000000 }, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = { 8, 9, 10, }, + .pp_count = 3, + .pp_chg_id = INT_MIN, }, + + { .n = "DSI_gclk", + .id = 103, + .r = {.max = 27000000}, + .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), }, + .pp_mux_table = {5}, + .pp_count = 1, + .pp_chg_id = INT_MIN,}, + + { .n = "I3CC_gclk", + .id = 105, + .r = {.max = 125000000}, + .pp = { PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), + PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), }, + .pp_mux_table = {8, 9, 10, }, + .pp_count = 3, + .pp_chg_id = INT_MIN,}, +}; + +/* MCK0 characteristics. */ +static const struct clk_master_characteristics mck0_characteristics = { + .output = {.min = 32768, .max = 200000000}, + .divisors = {1, 2, 4, 3, 5}, + .have_div3_pres = 1, +}; + +/* MCK0 layout. */ +static const struct clk_master_layout mck0_layout = { + .mask = 0x773, + .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 sama7d65_pcr_layout = { + .offset = 0x88, + .cmd = BIT(31), + .gckcss_mask = GENMASK(12, 8), + .pid_mask = GENMASK(6, 0), +}; + +enum clock_count { + CLK_CNT_SYSTEM = 15 + 1, + CLK_CNT_PERIPH = 104 + 1, + CLK_CNT_GCK = 105 + 1, +}; + +static struct device *pmc_table[PMC_MCK5 + 1 + CLK_CNT_SYSTEM + CLK_CNT_PERIPH + CLK_CNT_GCK + + SOC_NUM_CLOCK_PROGRAMMABLE]; + +static int sam_pmc_register_pll(const struct device *dev, struct pmc_data *sama7d65_pmc) +{ + const struct sam_pmc_cfg *cfg = dev->config; + void *const regmap = cfg->reg; + struct device *clk; + int ret, i, j; + + for (i = 0; i < PLL_ID_MAX; i++) { + for (j = 0; j < 3; j++) { + const struct device *parent_hw; + + if (!sama7d65_plls[i][j].n) { + continue; + } + + switch (sama7d65_plls[i][j].t) { + case PLL_TYPE_FRAC: + switch (sama7d65_plls[i][j].p) { + case SAMA7D65_PLL_PARENT_MAINCK: + parent_hw = sama7d65_pmc->chws[PMC_MAIN]; + break; + case SAMA7D65_PLL_PARENT_MAIN_XTAL: + parent_hw = cfg->main_xtal; + break; + default: + /* Should not happen. */ + parent_hw = NULL; + break; + } + + ret = sam9x60_clk_register_frac_pll(regmap, + &pmc_pll_lock, + sama7d65_plls[i][j].n, + parent_hw, i, + sama7d65_plls[i][j].c, + sama7d65_plls[i][j].l, + &clk); + break; + + case PLL_TYPE_DIV: + ret = sam9x60_clk_register_div_pll(regmap, + &pmc_pll_lock, + sama7d65_plls[i][j].n, + sama7d65_plls[i][0].clk, i, + sama7d65_plls[i][j].c, + sama7d65_plls[i][j].l, + &clk); + break; + + default: + continue; + } + + if (ret) { + LOG_ERR("Register clock %s failed.", sama7d65_plls[i][j].n); + return ret; + } + + sama7d65_plls[i][j].clk = clk; + if (sama7d65_plls[i][j].eid) { + sama7d65_pmc->chws[sama7d65_plls[i][j].eid] = clk; + } + } + } + + return 0; +} + +static int sam_pmc_register_mckx(const struct device *dev, struct pmc_data *sama7d65_pmc) +{ + const struct sam_pmc_cfg *cfg = dev->config; + const struct device *parents[10]; + void *const regmap = cfg->reg; + uint32_t mux_table[8]; + struct device *clk; + int ret = 0; + int i, j; + + ret = clk_register_master_div(regmap, "mck0", sama7d65_plls[PLL_ID_CPU][1].clk, + &mck0_layout, &mck0_characteristics, &pmc_mck0_lock, 5, &clk); + if (ret) { + LOG_ERR("Register MCK0 clock failed."); + return ret; + } + sama7d65_mckx[PCK_PARENT_HW_MCK0].clk = sama7d65_pmc->chws[PMC_MCK] = clk; + + parents[0] = cfg->md_slck; + parents[1] = cfg->td_slck; + parents[2] = sama7d65_pmc->chws[PMC_MAIN]; + for (i = PCK_PARENT_HW_MCK1; i < ARRAY_SIZE(sama7d65_mckx); i++) { + uint8_t num_parents = 3 + sama7d65_mckx[i].ep_count; + struct device *tmp_parent_hws[8]; + + if (num_parents > ARRAY_SIZE(mux_table)) { + LOG_ERR("Array for mux table not enough"); + return -ENOMEM; + } + + SAMA7D65_INIT_TABLE(mux_table, 3); + SAMA7D65_FILL_TABLE(&mux_table[3], sama7d65_mckx[i].ep_mux_table, + sama7d65_mckx[i].ep_count); + for (j = 0; j < sama7d65_mckx[i].ep_count; j++) { + uint8_t pll_id = sama7d65_mckx[i].ep[j].pll_id; + uint8_t pll_compid = sama7d65_mckx[i].ep[j].pll_compid; + + tmp_parent_hws[j] = sama7d65_plls[pll_id][pll_compid].clk; + } + SAMA7D65_FILL_TABLE(&parents[3], tmp_parent_hws, sama7d65_mckx[i].ep_count); + + ret = clk_register_master(regmap, sama7d65_mckx[i].n, num_parents, parents, + mux_table, &pmc_mckX_lock, sama7d65_mckx[i].id, &clk); + if (ret) { + LOG_ERR("Register MCK%d clock failed.", i); + return ret; + } + + sama7d65_mckx[i].clk = clk; + if (sama7d65_mckx[i].eid) { + sama7d65_pmc->chws[sama7d65_mckx[i].eid] = clk; + } + } + + return 0; +} + +static int sam_pmc_register_generated(const struct device *dev, struct pmc_data *sama7d65_pmc) +{ + const struct sam_pmc_cfg *cfg = dev->config; + const struct device *parents[10]; + void *const regmap = cfg->reg; + uint32_t mux_table[8]; + struct device *clk; + int ret = 0; + int i, j; + + parents[0] = cfg->md_slck; + parents[1] = cfg->td_slck; + parents[2] = sama7d65_pmc->chws[PMC_MAIN]; + parents[3] = sama7d65_pmc->chws[PMC_MCK1]; + for (i = 0; i < ARRAY_SIZE(sama7d65_gck); i++) { + uint8_t num_parents = 4 + sama7d65_gck[i].pp_count; + struct device *tmp_parent_hws[8]; + + if (num_parents > ARRAY_SIZE(mux_table)) { + LOG_ERR("Array for mux table not enough"); + return -ENOMEM; + } + + SAMA7D65_INIT_TABLE(mux_table, 4); + SAMA7D65_FILL_TABLE(&mux_table[4], sama7d65_gck[i].pp_mux_table, + sama7d65_gck[i].pp_count); + for (j = 0; j < sama7d65_gck[i].pp_count; j++) { + uint8_t pll_id = sama7d65_gck[i].pp[j].pll_id; + uint8_t pll_compid = sama7d65_gck[i].pp[j].pll_compid; + + tmp_parent_hws[j] = sama7d65_plls[pll_id][pll_compid].clk; + } + SAMA7D65_FILL_TABLE(&parents[4], tmp_parent_hws, sama7d65_gck[i].pp_count); + + ret = clk_register_generated(regmap, &pmc_pcr_lock, + &sama7d65_pcr_layout, + sama7d65_gck[i].n, + parents, mux_table, + num_parents, + sama7d65_gck[i].id, + &sama7d65_gck[i].r, + sama7d65_gck[i].pp_chg_id, &clk); + if (ret) { + LOG_ERR("Register generated clock failed."); + return ret; + } + sama7d65_pmc->ghws[sama7d65_gck[i].id] = clk; + } + + return 0; +} + +void sam_pmc_setup(const struct device *dev) +{ + const struct sam_pmc_cfg *cfg = dev->config; + struct sam_pmc_data *data = dev->data; + const struct device *main_xtal = cfg->main_xtal; + const struct device *td_slck = cfg->td_slck; + const struct device *md_slck = cfg->md_slck; + + void *const regmap = cfg->reg; + const struct device *parents[10]; + struct pmc_data *sama7d65_pmc; + struct device *clk, *main_rc, *main_osc; + + uint32_t rate, bypass; + int ret, i; + + if (!td_slck || !md_slck || !main_xtal || !regmap) { + LOG_ERR("Incorrect parameters."); + return; + } + + if (CLK_CNT_SYSTEM != nck(sama7d65_systemck) || + CLK_CNT_PERIPH != nck(sama7d65_periphck) || + CLK_CNT_GCK != nck(sama7d65_gck)) { + LOG_ERR("Incorrect definitions could make array for pmc clocks not enough"); + return; + } + + sama7d65_pmc = pmc_data_allocate(PMC_MCK5 + 1, nck(sama7d65_systemck), + nck(sama7d65_periphck), nck(sama7d65_gck), + SOC_NUM_CLOCK_PROGRAMMABLE, &pmc_table[0]); + if (!sama7d65_pmc) { + LOG_ERR("allocate PMC data failed."); + return; + } + data->pmc = sama7d65_pmc; + + ret = clk_register_main_rc_osc(regmap, "main_rc_osc", MHZ(12), &main_rc); + if (ret) { + LOG_ERR("Register clock main_rc_osc failed."); + return; + } + + if (clock_control_get_rate(main_xtal, NULL, &rate)) { + LOG_ERR("get clock rate of main_xtal failed."); + return; + } + + bypass = 0; + ret = clk_register_main_osc(regmap, "main_osc", bypass, rate, &main_osc); + if (ret) { + LOG_ERR("Register clock main_osc failed."); + return; + } + + parents[0] = main_rc; + parents[1] = main_osc; + ret = clk_register_main(regmap, "mainck", parents, 2, &clk); + if (ret) { + LOG_ERR("Register clock mainck failed."); + return; + } + + sama7d65_pmc->chws[PMC_MAIN] = clk; + + ret = sam_pmc_register_pll(dev, sama7d65_pmc); + if (ret) { + return; + } + + ret = sam_pmc_register_mckx(dev, sama7d65_pmc); + if (ret) { + return; + } + + parents[0] = md_slck; + parents[1] = td_slck; + parents[2] = sama7d65_pmc->chws[PMC_MAIN]; + parents[3] = sama7d65_plls[PLL_ID_SYS][PLL_COMPID_DIV0].clk; + parents[4] = sama7d65_plls[PLL_ID_DDR][PLL_COMPID_DIV0].clk; + parents[5] = sama7d65_plls[PLL_ID_GPU][PLL_COMPID_DIV0].clk; + parents[6] = sama7d65_plls[PLL_ID_BAUD][PLL_COMPID_DIV0].clk; + parents[7] = sama7d65_plls[PLL_ID_AUDIO][PLL_COMPID_DIV0].clk; + parents[8] = sama7d65_plls[PLL_ID_ETH][PLL_COMPID_DIV0].clk; + for (i = 0; i < 8; i++) { + ret = clk_register_programmable(regmap, parents, 9, i, &programmable_layout, + sama7d65_prog_mux_table, &clk); + if (ret) { + LOG_ERR("Register programmable clock %d failed.", i); + return; + } + + sama7d65_pmc->pchws[i] = clk; + } + + for (i = 0; i < ARRAY_SIZE(sama7d65_systemck); i++) { + ret = clk_register_system(regmap, sama7d65_systemck[i].n, + sama7d65_pmc->pchws[i], + sama7d65_systemck[i].id, &clk); + if (ret) { + LOG_ERR("Register system clock %d failed.", i); + return; + } + + sama7d65_pmc->shws[sama7d65_systemck[i].id] = clk; + } + + for (i = 0; i < ARRAY_SIZE(sama7d65_periphck); i++) { + clk = sama7d65_mckx[sama7d65_periphck[i].p].clk; + ret = clk_register_peripheral(regmap, &pmc_pcr_lock, + &sama7d65_pcr_layout, + sama7d65_periphck[i].n, + clk, + sama7d65_periphck[i].id, + &sama7d65_periphck[i].r, + &clk); + if (ret) { + LOG_ERR("Register peripheral clock failed."); + return; + } + sama7d65_pmc->phws[sama7d65_periphck[i].id] = clk; + } + + ret = sam_pmc_register_generated(dev, sama7d65_pmc); + if (ret) { + return; + } + + LOG_DBG("Register PMC clocks successfully."); +} diff --git a/soc/microchip/sam/common/sama7g5.c b/soc/microchip/sam/common/sama7g5.c index dbcb0a07d096e..1bf28fe1f882d 100644 --- a/soc/microchip/sam/common/sama7g5.c +++ b/soc/microchip/sam/common/sama7g5.c @@ -7,7 +7,6 @@ #include #include -#include #include #include @@ -1154,11 +1153,7 @@ void sam_pmc_setup(const struct device *dev) parents[7] = sama7g5_plls[PLL_ID_AUDIO][PLL_COMPID_DIV0].clk; parents[8] = sama7g5_plls[PLL_ID_ETH][PLL_COMPID_DIV0].clk; for (i = 0; i < 8; i++) { - char name[6]; - - snprintf(name, sizeof(name), "prog%d", i); - - ret = clk_register_programmable(regmap, name, parents, + ret = clk_register_programmable(regmap, parents, 9, i, &programmable_layout, sama7g5_prog_mux_table, &clk); diff --git a/soc/microchip/sam/sama7d6/CMakeLists.txt b/soc/microchip/sam/sama7d6/CMakeLists.txt new file mode 100644 index 0000000000000..8d91aceb1f3a8 --- /dev/null +++ b/soc/microchip/sam/sama7d6/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries +# +# SPDX-License-Identifier: Apache-2.0 +# + +zephyr_sources(soc.c) +zephyr_include_directories(.) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/microchip/sam/sama7d6/Kconfig.defconfig b/soc/microchip/sam/sama7d6/Kconfig.defconfig new file mode 100644 index 0000000000000..ead3911c72cdd --- /dev/null +++ b/soc/microchip/sam/sama7d6/Kconfig.defconfig @@ -0,0 +1,17 @@ +# Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries +# +# SPDX-License-Identifier: Apache-2.0 +# + +if SOC_SERIES_SAMA7D6 + +config NUM_IRQS + default 189 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default $(dt_node_int_prop_int,/soc/timer@e1800000,clock-frequency) + +config MMU + default y + +endif # SOC_SERIES_SAMA7D6 diff --git a/soc/microchip/sam/sama7d6/Kconfig.soc b/soc/microchip/sam/sama7d6/Kconfig.soc new file mode 100644 index 0000000000000..df6cb8ffc4e87 --- /dev/null +++ b/soc/microchip/sam/sama7d6/Kconfig.soc @@ -0,0 +1,15 @@ +# Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries +# +# SPDX-License-Identifier: Apache-2.0 +# + +config SOC_SERIES_SAMA7D6 + bool + select SOC_FAMILY_MICROCHIP_SAM + help + Enable support for Microchip SAM Microprocessors. + +config SOC_SERIES + default "sama7d6" if SOC_SERIES_SAMA7D6 + +rsource "Kconfig.soc.sam*" diff --git a/soc/microchip/sam/sama7d6/Kconfig.soc.sama7d65 b/soc/microchip/sam/sama7d6/Kconfig.soc.sama7d65 new file mode 100644 index 0000000000000..3fc0616ea77cb --- /dev/null +++ b/soc/microchip/sam/sama7d6/Kconfig.soc.sama7d65 @@ -0,0 +1,11 @@ +# Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries +# +# SPDX-License-Identifier: Apache-2.0 +# + +config SOC_SAMA7D65 + bool + select SOC_SERIES_SAMA7D6 + +config SOC + default "sama7d65" if SOC_SAMA7D65 diff --git a/soc/microchip/sam/sama7d6/soc.c b/soc/microchip/sam/sama7d6/soc.c new file mode 100644 index 0000000000000..39339f362ba67 --- /dev/null +++ b/soc/microchip/sam/sama7d6/soc.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include +#include +#include + +#define MMU_REGION_FLEXCOM_DEFN(idx, n) \ + COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flx##n)), \ + (MMU_REGION_FLAT_ENTRY("flexcom"#n, FLEXCOM##n##_BASE_ADDRESS, 0x4000, \ + MT_STRONGLY_ORDERED | MPERM_R | MPERM_W),), \ + ()) + +static const struct arm_mmu_region mmu_regions[] = { + MMU_REGION_FLAT_ENTRY("vectors", CONFIG_KERNEL_VM_BASE, 0x1000, + MT_STRONGLY_ORDERED | MPERM_R | MPERM_X), + + FOR_EACH_IDX(MMU_REGION_FLEXCOM_DEFN, (), 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + + MMU_REGION_FLAT_ENTRY("gic", GIC_DISTRIBUTOR_BASE, 0x1100, + MT_STRONGLY_ORDERED | MPERM_R | MPERM_W), + + MMU_REGION_FLAT_ENTRY("pioa", PIO_BASE_ADDRESS, 0x4000, + MT_STRONGLY_ORDERED | MPERM_R | MPERM_W), + + MMU_REGION_FLAT_ENTRY("pit64b0", PIT64B0_BASE_ADDRESS, 0x4000, + MT_STRONGLY_ORDERED | MPERM_R | MPERM_W), + + MMU_REGION_FLAT_ENTRY("pmc", PMC_BASE_ADDRESS, 0x200, + MT_STRONGLY_ORDERED | MPERM_R | MPERM_W), + + MMU_REGION_FLAT_ENTRY("sckc", SCKC_BASE_ADDRESS, 0x4, + MT_STRONGLY_ORDERED | MPERM_R | MPERM_W), +}; + +const struct arm_mmu_config mmu_config = { + .num_regions = ARRAY_SIZE(mmu_regions), + .mmu_regions = mmu_regions, +}; + +void relocate_vector_table(void) +{ + write_vbar(CONFIG_KERNEL_VM_BASE); +} + +void soc_early_init_hook(void) +{ + /* Enable Generic clock for PIT64B0 for system tick */ + PMC_REGS->PMC_PCR = PMC_PCR_CMD(1) | PMC_PCR_GCLKEN(1) | PMC_PCR_EN(1) | + PMC_PCR_GCLKDIV(20 - 1) | PMC_PCR_GCLKCSS_MCK1 | + PMC_PCR_PID(ID_PIT64B0); +} diff --git a/soc/microchip/sam/sama7d6/soc.h b/soc/microchip/sam/sama7d6/soc.h new file mode 100644 index 0000000000000..35015e3b38e72 --- /dev/null +++ b/soc/microchip/sam/sama7d6/soc.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __SAMA7D6_SOC__H_ +#define __SAMA7D6_SOC__H_ + +#ifdef CONFIG_SOC_SAMA7D65 +#define __SAMA7D65__ +#endif + +#include "sam.h" + +/* number of clocks registered */ +#define SOC_NUM_CLOCK_PLL_FRAC 9 +#define SOC_NUM_CLOCK_PLL_DIV (SOC_NUM_CLOCK_PLL_FRAC + 1) /* AUDIO PLL: DIVPMC, DIVIO */ +#define SOC_NUM_CLOCK_MASTER 10 /* MCK 0 ~ 9 */ +#define SOC_NUM_CLOCK_PROGRAMMABLE 8 /* MCK 0 ~ 7 */ +#define SOC_NUM_CLOCK_SYSTEM 8 /* PCK 0 ~ 7 */ +#define SOC_NUM_CLOCK_PERIPHERAL 72 +#define SOC_NUM_CLOCK_GENERATED 44 + +#endif /* __SAMA7D6_SOC__H_ */ diff --git a/soc/microchip/sam/sama7g5/soc.h b/soc/microchip/sam/sama7g5/soc.h index cdacd1592f9d4..bc2c93b57e1e7 100644 --- a/soc/microchip/sam/sama7g5/soc.h +++ b/soc/microchip/sam/sama7g5/soc.h @@ -13,4 +13,13 @@ #include "sam.h" +/* number of clocks registered */ +#define SOC_NUM_CLOCK_PLL_FRAC 7 +#define SOC_NUM_CLOCK_PLL_DIV (SOC_NUM_CLOCK_PLL_FRAC + 1) /* AUDIO PLL: DIVPMC, DIVIO */ +#define SOC_NUM_CLOCK_MASTER 5 /* MCK 0 ~ 4 */ +#define SOC_NUM_CLOCK_PROGRAMMABLE 8 /* MCK 0 ~ 7 */ +#define SOC_NUM_CLOCK_SYSTEM 8 /* PCK 0 ~ 7 */ +#define SOC_NUM_CLOCK_PERIPHERAL 72 +#define SOC_NUM_CLOCK_GENERATED 46 + #endif /* __SAMA7G5_SOC__H_ */ diff --git a/soc/microchip/sam/soc.yml b/soc/microchip/sam/soc.yml index 8c180ee3c44ba..10387d9e60cd8 100644 --- a/soc/microchip/sam/soc.yml +++ b/soc/microchip/sam/soc.yml @@ -1,6 +1,9 @@ family: - name: microchip_sam series: + - name: sama7d6 + socs: + - name: sama7d65 - name: sama7g5 socs: - name: sama7g54 diff --git a/west.yml b/west.yml index 3634554334c3a..32a0f00aa4d83 100644 --- a/west.yml +++ b/west.yml @@ -195,7 +195,7 @@ manifest: groups: - hal - name: hal_microchip - revision: 32a79d481c056b2204a5701d5a5799f9e5130dd7 + revision: 0f72d7573468cc32f6baeebaa92fd04bebf7346a path: modules/hal/microchip groups: - hal