18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2010,2015 Broadcom 48c2ecf20Sopenharmony_ci * Copyright (C) 2012 Stephen Warren 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci/** 88c2ecf20Sopenharmony_ci * DOC: BCM2835 CPRMAN (clock manager for the "audio" domain) 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * The clock tree on the 2835 has several levels. There's a root 118c2ecf20Sopenharmony_ci * oscillator running at 19.2Mhz. After the oscillator there are 5 128c2ecf20Sopenharmony_ci * PLLs, roughly divided as "camera", "ARM", "core", "DSI displays", 138c2ecf20Sopenharmony_ci * and "HDMI displays". Those 5 PLLs each can divide their output to 148c2ecf20Sopenharmony_ci * produce up to 4 channels. Finally, there is the level of clocks to 158c2ecf20Sopenharmony_ci * be consumed by other hardware components (like "H264" or "HDMI 168c2ecf20Sopenharmony_ci * state machine"), which divide off of some subset of the PLL 178c2ecf20Sopenharmony_ci * channels. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * All of the clocks in the tree are exposed in the DT, because the DT 208c2ecf20Sopenharmony_ci * may want to make assignments of the final layer of clocks to the 218c2ecf20Sopenharmony_ci * PLL channels, and some components of the hardware will actually 228c2ecf20Sopenharmony_ci * skip layers of the tree (for example, the pixel clock comes 238c2ecf20Sopenharmony_ci * directly from the PLLH PIX channel without using a CM_*CTL clock 248c2ecf20Sopenharmony_ci * generator). 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 288c2ecf20Sopenharmony_ci#include <linux/clkdev.h> 298c2ecf20Sopenharmony_ci#include <linux/clk.h> 308c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 318c2ecf20Sopenharmony_ci#include <linux/delay.h> 328c2ecf20Sopenharmony_ci#include <linux/io.h> 338c2ecf20Sopenharmony_ci#include <linux/module.h> 348c2ecf20Sopenharmony_ci#include <linux/of_device.h> 358c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 368c2ecf20Sopenharmony_ci#include <linux/slab.h> 378c2ecf20Sopenharmony_ci#include <dt-bindings/clock/bcm2835.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define CM_PASSWORD 0x5a000000 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define CM_GNRICCTL 0x000 428c2ecf20Sopenharmony_ci#define CM_GNRICDIV 0x004 438c2ecf20Sopenharmony_ci# define CM_DIV_FRAC_BITS 12 448c2ecf20Sopenharmony_ci# define CM_DIV_FRAC_MASK GENMASK(CM_DIV_FRAC_BITS - 1, 0) 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define CM_VPUCTL 0x008 478c2ecf20Sopenharmony_ci#define CM_VPUDIV 0x00c 488c2ecf20Sopenharmony_ci#define CM_SYSCTL 0x010 498c2ecf20Sopenharmony_ci#define CM_SYSDIV 0x014 508c2ecf20Sopenharmony_ci#define CM_PERIACTL 0x018 518c2ecf20Sopenharmony_ci#define CM_PERIADIV 0x01c 528c2ecf20Sopenharmony_ci#define CM_PERIICTL 0x020 538c2ecf20Sopenharmony_ci#define CM_PERIIDIV 0x024 548c2ecf20Sopenharmony_ci#define CM_H264CTL 0x028 558c2ecf20Sopenharmony_ci#define CM_H264DIV 0x02c 568c2ecf20Sopenharmony_ci#define CM_ISPCTL 0x030 578c2ecf20Sopenharmony_ci#define CM_ISPDIV 0x034 588c2ecf20Sopenharmony_ci#define CM_V3DCTL 0x038 598c2ecf20Sopenharmony_ci#define CM_V3DDIV 0x03c 608c2ecf20Sopenharmony_ci#define CM_CAM0CTL 0x040 618c2ecf20Sopenharmony_ci#define CM_CAM0DIV 0x044 628c2ecf20Sopenharmony_ci#define CM_CAM1CTL 0x048 638c2ecf20Sopenharmony_ci#define CM_CAM1DIV 0x04c 648c2ecf20Sopenharmony_ci#define CM_CCP2CTL 0x050 658c2ecf20Sopenharmony_ci#define CM_CCP2DIV 0x054 668c2ecf20Sopenharmony_ci#define CM_DSI0ECTL 0x058 678c2ecf20Sopenharmony_ci#define CM_DSI0EDIV 0x05c 688c2ecf20Sopenharmony_ci#define CM_DSI0PCTL 0x060 698c2ecf20Sopenharmony_ci#define CM_DSI0PDIV 0x064 708c2ecf20Sopenharmony_ci#define CM_DPICTL 0x068 718c2ecf20Sopenharmony_ci#define CM_DPIDIV 0x06c 728c2ecf20Sopenharmony_ci#define CM_GP0CTL 0x070 738c2ecf20Sopenharmony_ci#define CM_GP0DIV 0x074 748c2ecf20Sopenharmony_ci#define CM_GP1CTL 0x078 758c2ecf20Sopenharmony_ci#define CM_GP1DIV 0x07c 768c2ecf20Sopenharmony_ci#define CM_GP2CTL 0x080 778c2ecf20Sopenharmony_ci#define CM_GP2DIV 0x084 788c2ecf20Sopenharmony_ci#define CM_HSMCTL 0x088 798c2ecf20Sopenharmony_ci#define CM_HSMDIV 0x08c 808c2ecf20Sopenharmony_ci#define CM_OTPCTL 0x090 818c2ecf20Sopenharmony_ci#define CM_OTPDIV 0x094 828c2ecf20Sopenharmony_ci#define CM_PCMCTL 0x098 838c2ecf20Sopenharmony_ci#define CM_PCMDIV 0x09c 848c2ecf20Sopenharmony_ci#define CM_PWMCTL 0x0a0 858c2ecf20Sopenharmony_ci#define CM_PWMDIV 0x0a4 868c2ecf20Sopenharmony_ci#define CM_SLIMCTL 0x0a8 878c2ecf20Sopenharmony_ci#define CM_SLIMDIV 0x0ac 888c2ecf20Sopenharmony_ci#define CM_SMICTL 0x0b0 898c2ecf20Sopenharmony_ci#define CM_SMIDIV 0x0b4 908c2ecf20Sopenharmony_ci/* no definition for 0x0b8 and 0x0bc */ 918c2ecf20Sopenharmony_ci#define CM_TCNTCTL 0x0c0 928c2ecf20Sopenharmony_ci# define CM_TCNT_SRC1_SHIFT 12 938c2ecf20Sopenharmony_ci#define CM_TCNTCNT 0x0c4 948c2ecf20Sopenharmony_ci#define CM_TECCTL 0x0c8 958c2ecf20Sopenharmony_ci#define CM_TECDIV 0x0cc 968c2ecf20Sopenharmony_ci#define CM_TD0CTL 0x0d0 978c2ecf20Sopenharmony_ci#define CM_TD0DIV 0x0d4 988c2ecf20Sopenharmony_ci#define CM_TD1CTL 0x0d8 998c2ecf20Sopenharmony_ci#define CM_TD1DIV 0x0dc 1008c2ecf20Sopenharmony_ci#define CM_TSENSCTL 0x0e0 1018c2ecf20Sopenharmony_ci#define CM_TSENSDIV 0x0e4 1028c2ecf20Sopenharmony_ci#define CM_TIMERCTL 0x0e8 1038c2ecf20Sopenharmony_ci#define CM_TIMERDIV 0x0ec 1048c2ecf20Sopenharmony_ci#define CM_UARTCTL 0x0f0 1058c2ecf20Sopenharmony_ci#define CM_UARTDIV 0x0f4 1068c2ecf20Sopenharmony_ci#define CM_VECCTL 0x0f8 1078c2ecf20Sopenharmony_ci#define CM_VECDIV 0x0fc 1088c2ecf20Sopenharmony_ci#define CM_PULSECTL 0x190 1098c2ecf20Sopenharmony_ci#define CM_PULSEDIV 0x194 1108c2ecf20Sopenharmony_ci#define CM_SDCCTL 0x1a8 1118c2ecf20Sopenharmony_ci#define CM_SDCDIV 0x1ac 1128c2ecf20Sopenharmony_ci#define CM_ARMCTL 0x1b0 1138c2ecf20Sopenharmony_ci#define CM_AVEOCTL 0x1b8 1148c2ecf20Sopenharmony_ci#define CM_AVEODIV 0x1bc 1158c2ecf20Sopenharmony_ci#define CM_EMMCCTL 0x1c0 1168c2ecf20Sopenharmony_ci#define CM_EMMCDIV 0x1c4 1178c2ecf20Sopenharmony_ci#define CM_EMMC2CTL 0x1d0 1188c2ecf20Sopenharmony_ci#define CM_EMMC2DIV 0x1d4 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/* General bits for the CM_*CTL regs */ 1218c2ecf20Sopenharmony_ci# define CM_ENABLE BIT(4) 1228c2ecf20Sopenharmony_ci# define CM_KILL BIT(5) 1238c2ecf20Sopenharmony_ci# define CM_GATE_BIT 6 1248c2ecf20Sopenharmony_ci# define CM_GATE BIT(CM_GATE_BIT) 1258c2ecf20Sopenharmony_ci# define CM_BUSY BIT(7) 1268c2ecf20Sopenharmony_ci# define CM_BUSYD BIT(8) 1278c2ecf20Sopenharmony_ci# define CM_FRAC BIT(9) 1288c2ecf20Sopenharmony_ci# define CM_SRC_SHIFT 0 1298c2ecf20Sopenharmony_ci# define CM_SRC_BITS 4 1308c2ecf20Sopenharmony_ci# define CM_SRC_MASK 0xf 1318c2ecf20Sopenharmony_ci# define CM_SRC_GND 0 1328c2ecf20Sopenharmony_ci# define CM_SRC_OSC 1 1338c2ecf20Sopenharmony_ci# define CM_SRC_TESTDEBUG0 2 1348c2ecf20Sopenharmony_ci# define CM_SRC_TESTDEBUG1 3 1358c2ecf20Sopenharmony_ci# define CM_SRC_PLLA_CORE 4 1368c2ecf20Sopenharmony_ci# define CM_SRC_PLLA_PER 4 1378c2ecf20Sopenharmony_ci# define CM_SRC_PLLC_CORE0 5 1388c2ecf20Sopenharmony_ci# define CM_SRC_PLLC_PER 5 1398c2ecf20Sopenharmony_ci# define CM_SRC_PLLC_CORE1 8 1408c2ecf20Sopenharmony_ci# define CM_SRC_PLLD_CORE 6 1418c2ecf20Sopenharmony_ci# define CM_SRC_PLLD_PER 6 1428c2ecf20Sopenharmony_ci# define CM_SRC_PLLH_AUX 7 1438c2ecf20Sopenharmony_ci# define CM_SRC_PLLC_CORE1 8 1448c2ecf20Sopenharmony_ci# define CM_SRC_PLLC_CORE2 9 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci#define CM_OSCCOUNT 0x100 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci#define CM_PLLA 0x104 1498c2ecf20Sopenharmony_ci# define CM_PLL_ANARST BIT(8) 1508c2ecf20Sopenharmony_ci# define CM_PLLA_HOLDPER BIT(7) 1518c2ecf20Sopenharmony_ci# define CM_PLLA_LOADPER BIT(6) 1528c2ecf20Sopenharmony_ci# define CM_PLLA_HOLDCORE BIT(5) 1538c2ecf20Sopenharmony_ci# define CM_PLLA_LOADCORE BIT(4) 1548c2ecf20Sopenharmony_ci# define CM_PLLA_HOLDCCP2 BIT(3) 1558c2ecf20Sopenharmony_ci# define CM_PLLA_LOADCCP2 BIT(2) 1568c2ecf20Sopenharmony_ci# define CM_PLLA_HOLDDSI0 BIT(1) 1578c2ecf20Sopenharmony_ci# define CM_PLLA_LOADDSI0 BIT(0) 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci#define CM_PLLC 0x108 1608c2ecf20Sopenharmony_ci# define CM_PLLC_HOLDPER BIT(7) 1618c2ecf20Sopenharmony_ci# define CM_PLLC_LOADPER BIT(6) 1628c2ecf20Sopenharmony_ci# define CM_PLLC_HOLDCORE2 BIT(5) 1638c2ecf20Sopenharmony_ci# define CM_PLLC_LOADCORE2 BIT(4) 1648c2ecf20Sopenharmony_ci# define CM_PLLC_HOLDCORE1 BIT(3) 1658c2ecf20Sopenharmony_ci# define CM_PLLC_LOADCORE1 BIT(2) 1668c2ecf20Sopenharmony_ci# define CM_PLLC_HOLDCORE0 BIT(1) 1678c2ecf20Sopenharmony_ci# define CM_PLLC_LOADCORE0 BIT(0) 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci#define CM_PLLD 0x10c 1708c2ecf20Sopenharmony_ci# define CM_PLLD_HOLDPER BIT(7) 1718c2ecf20Sopenharmony_ci# define CM_PLLD_LOADPER BIT(6) 1728c2ecf20Sopenharmony_ci# define CM_PLLD_HOLDCORE BIT(5) 1738c2ecf20Sopenharmony_ci# define CM_PLLD_LOADCORE BIT(4) 1748c2ecf20Sopenharmony_ci# define CM_PLLD_HOLDDSI1 BIT(3) 1758c2ecf20Sopenharmony_ci# define CM_PLLD_LOADDSI1 BIT(2) 1768c2ecf20Sopenharmony_ci# define CM_PLLD_HOLDDSI0 BIT(1) 1778c2ecf20Sopenharmony_ci# define CM_PLLD_LOADDSI0 BIT(0) 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci#define CM_PLLH 0x110 1808c2ecf20Sopenharmony_ci# define CM_PLLH_LOADRCAL BIT(2) 1818c2ecf20Sopenharmony_ci# define CM_PLLH_LOADAUX BIT(1) 1828c2ecf20Sopenharmony_ci# define CM_PLLH_LOADPIX BIT(0) 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci#define CM_LOCK 0x114 1858c2ecf20Sopenharmony_ci# define CM_LOCK_FLOCKH BIT(12) 1868c2ecf20Sopenharmony_ci# define CM_LOCK_FLOCKD BIT(11) 1878c2ecf20Sopenharmony_ci# define CM_LOCK_FLOCKC BIT(10) 1888c2ecf20Sopenharmony_ci# define CM_LOCK_FLOCKB BIT(9) 1898c2ecf20Sopenharmony_ci# define CM_LOCK_FLOCKA BIT(8) 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci#define CM_EVENT 0x118 1928c2ecf20Sopenharmony_ci#define CM_DSI1ECTL 0x158 1938c2ecf20Sopenharmony_ci#define CM_DSI1EDIV 0x15c 1948c2ecf20Sopenharmony_ci#define CM_DSI1PCTL 0x160 1958c2ecf20Sopenharmony_ci#define CM_DSI1PDIV 0x164 1968c2ecf20Sopenharmony_ci#define CM_DFTCTL 0x168 1978c2ecf20Sopenharmony_ci#define CM_DFTDIV 0x16c 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci#define CM_PLLB 0x170 2008c2ecf20Sopenharmony_ci# define CM_PLLB_HOLDARM BIT(1) 2018c2ecf20Sopenharmony_ci# define CM_PLLB_LOADARM BIT(0) 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci#define A2W_PLLA_CTRL 0x1100 2048c2ecf20Sopenharmony_ci#define A2W_PLLC_CTRL 0x1120 2058c2ecf20Sopenharmony_ci#define A2W_PLLD_CTRL 0x1140 2068c2ecf20Sopenharmony_ci#define A2W_PLLH_CTRL 0x1160 2078c2ecf20Sopenharmony_ci#define A2W_PLLB_CTRL 0x11e0 2088c2ecf20Sopenharmony_ci# define A2W_PLL_CTRL_PRST_DISABLE BIT(17) 2098c2ecf20Sopenharmony_ci# define A2W_PLL_CTRL_PWRDN BIT(16) 2108c2ecf20Sopenharmony_ci# define A2W_PLL_CTRL_PDIV_MASK 0x000007000 2118c2ecf20Sopenharmony_ci# define A2W_PLL_CTRL_PDIV_SHIFT 12 2128c2ecf20Sopenharmony_ci# define A2W_PLL_CTRL_NDIV_MASK 0x0000003ff 2138c2ecf20Sopenharmony_ci# define A2W_PLL_CTRL_NDIV_SHIFT 0 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci#define A2W_PLLA_ANA0 0x1010 2168c2ecf20Sopenharmony_ci#define A2W_PLLC_ANA0 0x1030 2178c2ecf20Sopenharmony_ci#define A2W_PLLD_ANA0 0x1050 2188c2ecf20Sopenharmony_ci#define A2W_PLLH_ANA0 0x1070 2198c2ecf20Sopenharmony_ci#define A2W_PLLB_ANA0 0x10f0 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci#define A2W_PLL_KA_SHIFT 7 2228c2ecf20Sopenharmony_ci#define A2W_PLL_KA_MASK GENMASK(9, 7) 2238c2ecf20Sopenharmony_ci#define A2W_PLL_KI_SHIFT 19 2248c2ecf20Sopenharmony_ci#define A2W_PLL_KI_MASK GENMASK(21, 19) 2258c2ecf20Sopenharmony_ci#define A2W_PLL_KP_SHIFT 15 2268c2ecf20Sopenharmony_ci#define A2W_PLL_KP_MASK GENMASK(18, 15) 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci#define A2W_PLLH_KA_SHIFT 19 2298c2ecf20Sopenharmony_ci#define A2W_PLLH_KA_MASK GENMASK(21, 19) 2308c2ecf20Sopenharmony_ci#define A2W_PLLH_KI_LOW_SHIFT 22 2318c2ecf20Sopenharmony_ci#define A2W_PLLH_KI_LOW_MASK GENMASK(23, 22) 2328c2ecf20Sopenharmony_ci#define A2W_PLLH_KI_HIGH_SHIFT 0 2338c2ecf20Sopenharmony_ci#define A2W_PLLH_KI_HIGH_MASK GENMASK(0, 0) 2348c2ecf20Sopenharmony_ci#define A2W_PLLH_KP_SHIFT 1 2358c2ecf20Sopenharmony_ci#define A2W_PLLH_KP_MASK GENMASK(4, 1) 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci#define A2W_XOSC_CTRL 0x1190 2388c2ecf20Sopenharmony_ci# define A2W_XOSC_CTRL_PLLB_ENABLE BIT(7) 2398c2ecf20Sopenharmony_ci# define A2W_XOSC_CTRL_PLLA_ENABLE BIT(6) 2408c2ecf20Sopenharmony_ci# define A2W_XOSC_CTRL_PLLD_ENABLE BIT(5) 2418c2ecf20Sopenharmony_ci# define A2W_XOSC_CTRL_DDR_ENABLE BIT(4) 2428c2ecf20Sopenharmony_ci# define A2W_XOSC_CTRL_CPR1_ENABLE BIT(3) 2438c2ecf20Sopenharmony_ci# define A2W_XOSC_CTRL_USB_ENABLE BIT(2) 2448c2ecf20Sopenharmony_ci# define A2W_XOSC_CTRL_HDMI_ENABLE BIT(1) 2458c2ecf20Sopenharmony_ci# define A2W_XOSC_CTRL_PLLC_ENABLE BIT(0) 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci#define A2W_PLLA_FRAC 0x1200 2488c2ecf20Sopenharmony_ci#define A2W_PLLC_FRAC 0x1220 2498c2ecf20Sopenharmony_ci#define A2W_PLLD_FRAC 0x1240 2508c2ecf20Sopenharmony_ci#define A2W_PLLH_FRAC 0x1260 2518c2ecf20Sopenharmony_ci#define A2W_PLLB_FRAC 0x12e0 2528c2ecf20Sopenharmony_ci# define A2W_PLL_FRAC_MASK ((1 << A2W_PLL_FRAC_BITS) - 1) 2538c2ecf20Sopenharmony_ci# define A2W_PLL_FRAC_BITS 20 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci#define A2W_PLL_CHANNEL_DISABLE BIT(8) 2568c2ecf20Sopenharmony_ci#define A2W_PLL_DIV_BITS 8 2578c2ecf20Sopenharmony_ci#define A2W_PLL_DIV_SHIFT 0 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci#define A2W_PLLA_DSI0 0x1300 2608c2ecf20Sopenharmony_ci#define A2W_PLLA_CORE 0x1400 2618c2ecf20Sopenharmony_ci#define A2W_PLLA_PER 0x1500 2628c2ecf20Sopenharmony_ci#define A2W_PLLA_CCP2 0x1600 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci#define A2W_PLLC_CORE2 0x1320 2658c2ecf20Sopenharmony_ci#define A2W_PLLC_CORE1 0x1420 2668c2ecf20Sopenharmony_ci#define A2W_PLLC_PER 0x1520 2678c2ecf20Sopenharmony_ci#define A2W_PLLC_CORE0 0x1620 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci#define A2W_PLLD_DSI0 0x1340 2708c2ecf20Sopenharmony_ci#define A2W_PLLD_CORE 0x1440 2718c2ecf20Sopenharmony_ci#define A2W_PLLD_PER 0x1540 2728c2ecf20Sopenharmony_ci#define A2W_PLLD_DSI1 0x1640 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci#define A2W_PLLH_AUX 0x1360 2758c2ecf20Sopenharmony_ci#define A2W_PLLH_RCAL 0x1460 2768c2ecf20Sopenharmony_ci#define A2W_PLLH_PIX 0x1560 2778c2ecf20Sopenharmony_ci#define A2W_PLLH_STS 0x1660 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci#define A2W_PLLH_CTRLR 0x1960 2808c2ecf20Sopenharmony_ci#define A2W_PLLH_FRACR 0x1a60 2818c2ecf20Sopenharmony_ci#define A2W_PLLH_AUXR 0x1b60 2828c2ecf20Sopenharmony_ci#define A2W_PLLH_RCALR 0x1c60 2838c2ecf20Sopenharmony_ci#define A2W_PLLH_PIXR 0x1d60 2848c2ecf20Sopenharmony_ci#define A2W_PLLH_STSR 0x1e60 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci#define A2W_PLLB_ARM 0x13e0 2878c2ecf20Sopenharmony_ci#define A2W_PLLB_SP0 0x14e0 2888c2ecf20Sopenharmony_ci#define A2W_PLLB_SP1 0x15e0 2898c2ecf20Sopenharmony_ci#define A2W_PLLB_SP2 0x16e0 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci#define LOCK_TIMEOUT_NS 100000000 2928c2ecf20Sopenharmony_ci#define BCM2835_MAX_FB_RATE 1750000000u 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci#define SOC_BCM2835 BIT(0) 2958c2ecf20Sopenharmony_ci#define SOC_BCM2711 BIT(1) 2968c2ecf20Sopenharmony_ci#define SOC_ALL (SOC_BCM2835 | SOC_BCM2711) 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci/* 2998c2ecf20Sopenharmony_ci * Names of clocks used within the driver that need to be replaced 3008c2ecf20Sopenharmony_ci * with an external parent's name. This array is in the order that 3018c2ecf20Sopenharmony_ci * the clocks node in the DT references external clocks. 3028c2ecf20Sopenharmony_ci */ 3038c2ecf20Sopenharmony_cistatic const char *const cprman_parent_names[] = { 3048c2ecf20Sopenharmony_ci "xosc", 3058c2ecf20Sopenharmony_ci "dsi0_byte", 3068c2ecf20Sopenharmony_ci "dsi0_ddr2", 3078c2ecf20Sopenharmony_ci "dsi0_ddr", 3088c2ecf20Sopenharmony_ci "dsi1_byte", 3098c2ecf20Sopenharmony_ci "dsi1_ddr2", 3108c2ecf20Sopenharmony_ci "dsi1_ddr", 3118c2ecf20Sopenharmony_ci}; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistruct bcm2835_cprman { 3148c2ecf20Sopenharmony_ci struct device *dev; 3158c2ecf20Sopenharmony_ci void __iomem *regs; 3168c2ecf20Sopenharmony_ci spinlock_t regs_lock; /* spinlock for all clocks */ 3178c2ecf20Sopenharmony_ci unsigned int soc; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* 3208c2ecf20Sopenharmony_ci * Real names of cprman clock parents looked up through 3218c2ecf20Sopenharmony_ci * of_clk_get_parent_name(), which will be used in the 3228c2ecf20Sopenharmony_ci * parent_names[] arrays for clock registration. 3238c2ecf20Sopenharmony_ci */ 3248c2ecf20Sopenharmony_ci const char *real_parent_names[ARRAY_SIZE(cprman_parent_names)]; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* Must be last */ 3278c2ecf20Sopenharmony_ci struct clk_hw_onecell_data onecell; 3288c2ecf20Sopenharmony_ci}; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistruct cprman_plat_data { 3318c2ecf20Sopenharmony_ci unsigned int soc; 3328c2ecf20Sopenharmony_ci}; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic inline void cprman_write(struct bcm2835_cprman *cprman, u32 reg, u32 val) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci writel(CM_PASSWORD | val, cprman->regs + reg); 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic inline u32 cprman_read(struct bcm2835_cprman *cprman, u32 reg) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci return readl(cprman->regs + reg); 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci/* Does a cycle of measuring a clock through the TCNT clock, which may 3458c2ecf20Sopenharmony_ci * source from many other clocks in the system. 3468c2ecf20Sopenharmony_ci */ 3478c2ecf20Sopenharmony_cistatic unsigned long bcm2835_measure_tcnt_mux(struct bcm2835_cprman *cprman, 3488c2ecf20Sopenharmony_ci u32 tcnt_mux) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci u32 osccount = 19200; /* 1ms */ 3518c2ecf20Sopenharmony_ci u32 count; 3528c2ecf20Sopenharmony_ci ktime_t timeout; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci spin_lock(&cprman->regs_lock); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci cprman_write(cprman, CM_TCNTCTL, CM_KILL); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci cprman_write(cprman, CM_TCNTCTL, 3598c2ecf20Sopenharmony_ci (tcnt_mux & CM_SRC_MASK) | 3608c2ecf20Sopenharmony_ci (tcnt_mux >> CM_SRC_BITS) << CM_TCNT_SRC1_SHIFT); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci cprman_write(cprman, CM_OSCCOUNT, osccount); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci /* do a kind delay at the start */ 3658c2ecf20Sopenharmony_ci mdelay(1); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci /* Finish off whatever is left of OSCCOUNT */ 3688c2ecf20Sopenharmony_ci timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS); 3698c2ecf20Sopenharmony_ci while (cprman_read(cprman, CM_OSCCOUNT)) { 3708c2ecf20Sopenharmony_ci if (ktime_after(ktime_get(), timeout)) { 3718c2ecf20Sopenharmony_ci dev_err(cprman->dev, "timeout waiting for OSCCOUNT\n"); 3728c2ecf20Sopenharmony_ci count = 0; 3738c2ecf20Sopenharmony_ci goto out; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci cpu_relax(); 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci /* Wait for BUSY to clear. */ 3798c2ecf20Sopenharmony_ci timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS); 3808c2ecf20Sopenharmony_ci while (cprman_read(cprman, CM_TCNTCTL) & CM_BUSY) { 3818c2ecf20Sopenharmony_ci if (ktime_after(ktime_get(), timeout)) { 3828c2ecf20Sopenharmony_ci dev_err(cprman->dev, "timeout waiting for !BUSY\n"); 3838c2ecf20Sopenharmony_ci count = 0; 3848c2ecf20Sopenharmony_ci goto out; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci cpu_relax(); 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci count = cprman_read(cprman, CM_TCNTCNT); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci cprman_write(cprman, CM_TCNTCTL, 0); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ciout: 3948c2ecf20Sopenharmony_ci spin_unlock(&cprman->regs_lock); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci return count * 1000; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic void bcm2835_debugfs_regset(struct bcm2835_cprman *cprman, u32 base, 4008c2ecf20Sopenharmony_ci const struct debugfs_reg32 *regs, 4018c2ecf20Sopenharmony_ci size_t nregs, struct dentry *dentry) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci struct debugfs_regset32 *regset; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci regset = devm_kzalloc(cprman->dev, sizeof(*regset), GFP_KERNEL); 4068c2ecf20Sopenharmony_ci if (!regset) 4078c2ecf20Sopenharmony_ci return; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci regset->regs = regs; 4108c2ecf20Sopenharmony_ci regset->nregs = nregs; 4118c2ecf20Sopenharmony_ci regset->base = cprman->regs + base; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci debugfs_create_regset32("regdump", S_IRUGO, dentry, regset); 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistruct bcm2835_pll_data { 4178c2ecf20Sopenharmony_ci const char *name; 4188c2ecf20Sopenharmony_ci u32 cm_ctrl_reg; 4198c2ecf20Sopenharmony_ci u32 a2w_ctrl_reg; 4208c2ecf20Sopenharmony_ci u32 frac_reg; 4218c2ecf20Sopenharmony_ci u32 ana_reg_base; 4228c2ecf20Sopenharmony_ci u32 reference_enable_mask; 4238c2ecf20Sopenharmony_ci /* Bit in CM_LOCK to indicate when the PLL has locked. */ 4248c2ecf20Sopenharmony_ci u32 lock_mask; 4258c2ecf20Sopenharmony_ci u32 flags; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci const struct bcm2835_pll_ana_bits *ana; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci unsigned long min_rate; 4308c2ecf20Sopenharmony_ci unsigned long max_rate; 4318c2ecf20Sopenharmony_ci /* 4328c2ecf20Sopenharmony_ci * Highest rate for the VCO before we have to use the 4338c2ecf20Sopenharmony_ci * pre-divide-by-2. 4348c2ecf20Sopenharmony_ci */ 4358c2ecf20Sopenharmony_ci unsigned long max_fb_rate; 4368c2ecf20Sopenharmony_ci}; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistruct bcm2835_pll_ana_bits { 4398c2ecf20Sopenharmony_ci u32 mask0; 4408c2ecf20Sopenharmony_ci u32 set0; 4418c2ecf20Sopenharmony_ci u32 mask1; 4428c2ecf20Sopenharmony_ci u32 set1; 4438c2ecf20Sopenharmony_ci u32 mask3; 4448c2ecf20Sopenharmony_ci u32 set3; 4458c2ecf20Sopenharmony_ci u32 fb_prediv_mask; 4468c2ecf20Sopenharmony_ci}; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic const struct bcm2835_pll_ana_bits bcm2835_ana_default = { 4498c2ecf20Sopenharmony_ci .mask0 = 0, 4508c2ecf20Sopenharmony_ci .set0 = 0, 4518c2ecf20Sopenharmony_ci .mask1 = A2W_PLL_KI_MASK | A2W_PLL_KP_MASK, 4528c2ecf20Sopenharmony_ci .set1 = (2 << A2W_PLL_KI_SHIFT) | (8 << A2W_PLL_KP_SHIFT), 4538c2ecf20Sopenharmony_ci .mask3 = A2W_PLL_KA_MASK, 4548c2ecf20Sopenharmony_ci .set3 = (2 << A2W_PLL_KA_SHIFT), 4558c2ecf20Sopenharmony_ci .fb_prediv_mask = BIT(14), 4568c2ecf20Sopenharmony_ci}; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic const struct bcm2835_pll_ana_bits bcm2835_ana_pllh = { 4598c2ecf20Sopenharmony_ci .mask0 = A2W_PLLH_KA_MASK | A2W_PLLH_KI_LOW_MASK, 4608c2ecf20Sopenharmony_ci .set0 = (2 << A2W_PLLH_KA_SHIFT) | (2 << A2W_PLLH_KI_LOW_SHIFT), 4618c2ecf20Sopenharmony_ci .mask1 = A2W_PLLH_KI_HIGH_MASK | A2W_PLLH_KP_MASK, 4628c2ecf20Sopenharmony_ci .set1 = (6 << A2W_PLLH_KP_SHIFT), 4638c2ecf20Sopenharmony_ci .mask3 = 0, 4648c2ecf20Sopenharmony_ci .set3 = 0, 4658c2ecf20Sopenharmony_ci .fb_prediv_mask = BIT(11), 4668c2ecf20Sopenharmony_ci}; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistruct bcm2835_pll_divider_data { 4698c2ecf20Sopenharmony_ci const char *name; 4708c2ecf20Sopenharmony_ci const char *source_pll; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci u32 cm_reg; 4738c2ecf20Sopenharmony_ci u32 a2w_reg; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci u32 load_mask; 4768c2ecf20Sopenharmony_ci u32 hold_mask; 4778c2ecf20Sopenharmony_ci u32 fixed_divider; 4788c2ecf20Sopenharmony_ci u32 flags; 4798c2ecf20Sopenharmony_ci}; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistruct bcm2835_clock_data { 4828c2ecf20Sopenharmony_ci const char *name; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci const char *const *parents; 4858c2ecf20Sopenharmony_ci int num_mux_parents; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* Bitmap encoding which parents accept rate change propagation. */ 4888c2ecf20Sopenharmony_ci unsigned int set_rate_parent; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci u32 ctl_reg; 4918c2ecf20Sopenharmony_ci u32 div_reg; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci /* Number of integer bits in the divider */ 4948c2ecf20Sopenharmony_ci u32 int_bits; 4958c2ecf20Sopenharmony_ci /* Number of fractional bits in the divider */ 4968c2ecf20Sopenharmony_ci u32 frac_bits; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci u32 flags; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci bool is_vpu_clock; 5018c2ecf20Sopenharmony_ci bool is_mash_clock; 5028c2ecf20Sopenharmony_ci bool low_jitter; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci u32 tcnt_mux; 5058c2ecf20Sopenharmony_ci}; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cistruct bcm2835_gate_data { 5088c2ecf20Sopenharmony_ci const char *name; 5098c2ecf20Sopenharmony_ci const char *parent; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci u32 ctl_reg; 5128c2ecf20Sopenharmony_ci}; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistruct bcm2835_pll { 5158c2ecf20Sopenharmony_ci struct clk_hw hw; 5168c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman; 5178c2ecf20Sopenharmony_ci const struct bcm2835_pll_data *data; 5188c2ecf20Sopenharmony_ci}; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic int bcm2835_pll_is_on(struct clk_hw *hw) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw); 5238c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman = pll->cprman; 5248c2ecf20Sopenharmony_ci const struct bcm2835_pll_data *data = pll->data; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci return cprman_read(cprman, data->a2w_ctrl_reg) & 5278c2ecf20Sopenharmony_ci A2W_PLL_CTRL_PRST_DISABLE; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic u32 bcm2835_pll_get_prediv_mask(struct bcm2835_cprman *cprman, 5318c2ecf20Sopenharmony_ci const struct bcm2835_pll_data *data) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci /* 5348c2ecf20Sopenharmony_ci * On BCM2711 there isn't a pre-divisor available in the PLL feedback 5358c2ecf20Sopenharmony_ci * loop. Bits 13:14 of ANA1 (PLLA,PLLB,PLLC,PLLD) have been re-purposed 5368c2ecf20Sopenharmony_ci * for to for VCO RANGE bits. 5378c2ecf20Sopenharmony_ci */ 5388c2ecf20Sopenharmony_ci if (cprman->soc & SOC_BCM2711) 5398c2ecf20Sopenharmony_ci return 0; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci return data->ana->fb_prediv_mask; 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistatic void bcm2835_pll_choose_ndiv_and_fdiv(unsigned long rate, 5458c2ecf20Sopenharmony_ci unsigned long parent_rate, 5468c2ecf20Sopenharmony_ci u32 *ndiv, u32 *fdiv) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci u64 div; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci div = (u64)rate << A2W_PLL_FRAC_BITS; 5518c2ecf20Sopenharmony_ci do_div(div, parent_rate); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci *ndiv = div >> A2W_PLL_FRAC_BITS; 5548c2ecf20Sopenharmony_ci *fdiv = div & ((1 << A2W_PLL_FRAC_BITS) - 1); 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic long bcm2835_pll_rate_from_divisors(unsigned long parent_rate, 5588c2ecf20Sopenharmony_ci u32 ndiv, u32 fdiv, u32 pdiv) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci u64 rate; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci if (pdiv == 0) 5638c2ecf20Sopenharmony_ci return 0; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci rate = (u64)parent_rate * ((ndiv << A2W_PLL_FRAC_BITS) + fdiv); 5668c2ecf20Sopenharmony_ci do_div(rate, pdiv); 5678c2ecf20Sopenharmony_ci return rate >> A2W_PLL_FRAC_BITS; 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cistatic long bcm2835_pll_round_rate(struct clk_hw *hw, unsigned long rate, 5718c2ecf20Sopenharmony_ci unsigned long *parent_rate) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw); 5748c2ecf20Sopenharmony_ci const struct bcm2835_pll_data *data = pll->data; 5758c2ecf20Sopenharmony_ci u32 ndiv, fdiv; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci rate = clamp(rate, data->min_rate, data->max_rate); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci bcm2835_pll_choose_ndiv_and_fdiv(rate, *parent_rate, &ndiv, &fdiv); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci return bcm2835_pll_rate_from_divisors(*parent_rate, ndiv, fdiv, 1); 5828c2ecf20Sopenharmony_ci} 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_cistatic unsigned long bcm2835_pll_get_rate(struct clk_hw *hw, 5858c2ecf20Sopenharmony_ci unsigned long parent_rate) 5868c2ecf20Sopenharmony_ci{ 5878c2ecf20Sopenharmony_ci struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw); 5888c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman = pll->cprman; 5898c2ecf20Sopenharmony_ci const struct bcm2835_pll_data *data = pll->data; 5908c2ecf20Sopenharmony_ci u32 a2wctrl = cprman_read(cprman, data->a2w_ctrl_reg); 5918c2ecf20Sopenharmony_ci u32 ndiv, pdiv, fdiv; 5928c2ecf20Sopenharmony_ci bool using_prediv; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci if (parent_rate == 0) 5958c2ecf20Sopenharmony_ci return 0; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci fdiv = cprman_read(cprman, data->frac_reg) & A2W_PLL_FRAC_MASK; 5988c2ecf20Sopenharmony_ci ndiv = (a2wctrl & A2W_PLL_CTRL_NDIV_MASK) >> A2W_PLL_CTRL_NDIV_SHIFT; 5998c2ecf20Sopenharmony_ci pdiv = (a2wctrl & A2W_PLL_CTRL_PDIV_MASK) >> A2W_PLL_CTRL_PDIV_SHIFT; 6008c2ecf20Sopenharmony_ci using_prediv = cprman_read(cprman, data->ana_reg_base + 4) & 6018c2ecf20Sopenharmony_ci bcm2835_pll_get_prediv_mask(cprman, data); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci if (using_prediv) { 6048c2ecf20Sopenharmony_ci ndiv *= 2; 6058c2ecf20Sopenharmony_ci fdiv *= 2; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci return bcm2835_pll_rate_from_divisors(parent_rate, ndiv, fdiv, pdiv); 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_cistatic void bcm2835_pll_off(struct clk_hw *hw) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw); 6148c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman = pll->cprman; 6158c2ecf20Sopenharmony_ci const struct bcm2835_pll_data *data = pll->data; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci spin_lock(&cprman->regs_lock); 6188c2ecf20Sopenharmony_ci cprman_write(cprman, data->cm_ctrl_reg, CM_PLL_ANARST); 6198c2ecf20Sopenharmony_ci cprman_write(cprman, data->a2w_ctrl_reg, 6208c2ecf20Sopenharmony_ci cprman_read(cprman, data->a2w_ctrl_reg) | 6218c2ecf20Sopenharmony_ci A2W_PLL_CTRL_PWRDN); 6228c2ecf20Sopenharmony_ci spin_unlock(&cprman->regs_lock); 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic int bcm2835_pll_on(struct clk_hw *hw) 6268c2ecf20Sopenharmony_ci{ 6278c2ecf20Sopenharmony_ci struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw); 6288c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman = pll->cprman; 6298c2ecf20Sopenharmony_ci const struct bcm2835_pll_data *data = pll->data; 6308c2ecf20Sopenharmony_ci ktime_t timeout; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci cprman_write(cprman, data->a2w_ctrl_reg, 6338c2ecf20Sopenharmony_ci cprman_read(cprman, data->a2w_ctrl_reg) & 6348c2ecf20Sopenharmony_ci ~A2W_PLL_CTRL_PWRDN); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci /* Take the PLL out of reset. */ 6378c2ecf20Sopenharmony_ci spin_lock(&cprman->regs_lock); 6388c2ecf20Sopenharmony_ci cprman_write(cprman, data->cm_ctrl_reg, 6398c2ecf20Sopenharmony_ci cprman_read(cprman, data->cm_ctrl_reg) & ~CM_PLL_ANARST); 6408c2ecf20Sopenharmony_ci spin_unlock(&cprman->regs_lock); 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci /* Wait for the PLL to lock. */ 6438c2ecf20Sopenharmony_ci timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS); 6448c2ecf20Sopenharmony_ci while (!(cprman_read(cprman, CM_LOCK) & data->lock_mask)) { 6458c2ecf20Sopenharmony_ci if (ktime_after(ktime_get(), timeout)) { 6468c2ecf20Sopenharmony_ci dev_err(cprman->dev, "%s: couldn't lock PLL\n", 6478c2ecf20Sopenharmony_ci clk_hw_get_name(hw)); 6488c2ecf20Sopenharmony_ci return -ETIMEDOUT; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci cpu_relax(); 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci cprman_write(cprman, data->a2w_ctrl_reg, 6558c2ecf20Sopenharmony_ci cprman_read(cprman, data->a2w_ctrl_reg) | 6568c2ecf20Sopenharmony_ci A2W_PLL_CTRL_PRST_DISABLE); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci return 0; 6598c2ecf20Sopenharmony_ci} 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_cistatic void 6628c2ecf20Sopenharmony_cibcm2835_pll_write_ana(struct bcm2835_cprman *cprman, u32 ana_reg_base, u32 *ana) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci int i; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci /* 6678c2ecf20Sopenharmony_ci * ANA register setup is done as a series of writes to 6688c2ecf20Sopenharmony_ci * ANA3-ANA0, in that order. This lets us write all 4 6698c2ecf20Sopenharmony_ci * registers as a single cycle of the serdes interface (taking 6708c2ecf20Sopenharmony_ci * 100 xosc clocks), whereas if we were to update ana0, 1, and 6718c2ecf20Sopenharmony_ci * 3 individually through their partial-write registers, each 6728c2ecf20Sopenharmony_ci * would be their own serdes cycle. 6738c2ecf20Sopenharmony_ci */ 6748c2ecf20Sopenharmony_ci for (i = 3; i >= 0; i--) 6758c2ecf20Sopenharmony_ci cprman_write(cprman, ana_reg_base + i * 4, ana[i]); 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_cistatic int bcm2835_pll_set_rate(struct clk_hw *hw, 6798c2ecf20Sopenharmony_ci unsigned long rate, unsigned long parent_rate) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw); 6828c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman = pll->cprman; 6838c2ecf20Sopenharmony_ci const struct bcm2835_pll_data *data = pll->data; 6848c2ecf20Sopenharmony_ci u32 prediv_mask = bcm2835_pll_get_prediv_mask(cprman, data); 6858c2ecf20Sopenharmony_ci bool was_using_prediv, use_fb_prediv, do_ana_setup_first; 6868c2ecf20Sopenharmony_ci u32 ndiv, fdiv, a2w_ctl; 6878c2ecf20Sopenharmony_ci u32 ana[4]; 6888c2ecf20Sopenharmony_ci int i; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci if (rate > data->max_fb_rate) { 6918c2ecf20Sopenharmony_ci use_fb_prediv = true; 6928c2ecf20Sopenharmony_ci rate /= 2; 6938c2ecf20Sopenharmony_ci } else { 6948c2ecf20Sopenharmony_ci use_fb_prediv = false; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci bcm2835_pll_choose_ndiv_and_fdiv(rate, parent_rate, &ndiv, &fdiv); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci for (i = 3; i >= 0; i--) 7008c2ecf20Sopenharmony_ci ana[i] = cprman_read(cprman, data->ana_reg_base + i * 4); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci was_using_prediv = ana[1] & prediv_mask; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci ana[0] &= ~data->ana->mask0; 7058c2ecf20Sopenharmony_ci ana[0] |= data->ana->set0; 7068c2ecf20Sopenharmony_ci ana[1] &= ~data->ana->mask1; 7078c2ecf20Sopenharmony_ci ana[1] |= data->ana->set1; 7088c2ecf20Sopenharmony_ci ana[3] &= ~data->ana->mask3; 7098c2ecf20Sopenharmony_ci ana[3] |= data->ana->set3; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci if (was_using_prediv && !use_fb_prediv) { 7128c2ecf20Sopenharmony_ci ana[1] &= ~prediv_mask; 7138c2ecf20Sopenharmony_ci do_ana_setup_first = true; 7148c2ecf20Sopenharmony_ci } else if (!was_using_prediv && use_fb_prediv) { 7158c2ecf20Sopenharmony_ci ana[1] |= prediv_mask; 7168c2ecf20Sopenharmony_ci do_ana_setup_first = false; 7178c2ecf20Sopenharmony_ci } else { 7188c2ecf20Sopenharmony_ci do_ana_setup_first = true; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci /* Unmask the reference clock from the oscillator. */ 7228c2ecf20Sopenharmony_ci spin_lock(&cprman->regs_lock); 7238c2ecf20Sopenharmony_ci cprman_write(cprman, A2W_XOSC_CTRL, 7248c2ecf20Sopenharmony_ci cprman_read(cprman, A2W_XOSC_CTRL) | 7258c2ecf20Sopenharmony_ci data->reference_enable_mask); 7268c2ecf20Sopenharmony_ci spin_unlock(&cprman->regs_lock); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci if (do_ana_setup_first) 7298c2ecf20Sopenharmony_ci bcm2835_pll_write_ana(cprman, data->ana_reg_base, ana); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci /* Set the PLL multiplier from the oscillator. */ 7328c2ecf20Sopenharmony_ci cprman_write(cprman, data->frac_reg, fdiv); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci a2w_ctl = cprman_read(cprman, data->a2w_ctrl_reg); 7358c2ecf20Sopenharmony_ci a2w_ctl &= ~A2W_PLL_CTRL_NDIV_MASK; 7368c2ecf20Sopenharmony_ci a2w_ctl |= ndiv << A2W_PLL_CTRL_NDIV_SHIFT; 7378c2ecf20Sopenharmony_ci a2w_ctl &= ~A2W_PLL_CTRL_PDIV_MASK; 7388c2ecf20Sopenharmony_ci a2w_ctl |= 1 << A2W_PLL_CTRL_PDIV_SHIFT; 7398c2ecf20Sopenharmony_ci cprman_write(cprman, data->a2w_ctrl_reg, a2w_ctl); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci if (!do_ana_setup_first) 7428c2ecf20Sopenharmony_ci bcm2835_pll_write_ana(cprman, data->ana_reg_base, ana); 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci return 0; 7458c2ecf20Sopenharmony_ci} 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_cistatic void bcm2835_pll_debug_init(struct clk_hw *hw, 7488c2ecf20Sopenharmony_ci struct dentry *dentry) 7498c2ecf20Sopenharmony_ci{ 7508c2ecf20Sopenharmony_ci struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw); 7518c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman = pll->cprman; 7528c2ecf20Sopenharmony_ci const struct bcm2835_pll_data *data = pll->data; 7538c2ecf20Sopenharmony_ci struct debugfs_reg32 *regs; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci regs = devm_kcalloc(cprman->dev, 7, sizeof(*regs), GFP_KERNEL); 7568c2ecf20Sopenharmony_ci if (!regs) 7578c2ecf20Sopenharmony_ci return; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci regs[0].name = "cm_ctrl"; 7608c2ecf20Sopenharmony_ci regs[0].offset = data->cm_ctrl_reg; 7618c2ecf20Sopenharmony_ci regs[1].name = "a2w_ctrl"; 7628c2ecf20Sopenharmony_ci regs[1].offset = data->a2w_ctrl_reg; 7638c2ecf20Sopenharmony_ci regs[2].name = "frac"; 7648c2ecf20Sopenharmony_ci regs[2].offset = data->frac_reg; 7658c2ecf20Sopenharmony_ci regs[3].name = "ana0"; 7668c2ecf20Sopenharmony_ci regs[3].offset = data->ana_reg_base + 0 * 4; 7678c2ecf20Sopenharmony_ci regs[4].name = "ana1"; 7688c2ecf20Sopenharmony_ci regs[4].offset = data->ana_reg_base + 1 * 4; 7698c2ecf20Sopenharmony_ci regs[5].name = "ana2"; 7708c2ecf20Sopenharmony_ci regs[5].offset = data->ana_reg_base + 2 * 4; 7718c2ecf20Sopenharmony_ci regs[6].name = "ana3"; 7728c2ecf20Sopenharmony_ci regs[6].offset = data->ana_reg_base + 3 * 4; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci bcm2835_debugfs_regset(cprman, 0, regs, 7, dentry); 7758c2ecf20Sopenharmony_ci} 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_cistatic const struct clk_ops bcm2835_pll_clk_ops = { 7788c2ecf20Sopenharmony_ci .is_prepared = bcm2835_pll_is_on, 7798c2ecf20Sopenharmony_ci .prepare = bcm2835_pll_on, 7808c2ecf20Sopenharmony_ci .unprepare = bcm2835_pll_off, 7818c2ecf20Sopenharmony_ci .recalc_rate = bcm2835_pll_get_rate, 7828c2ecf20Sopenharmony_ci .set_rate = bcm2835_pll_set_rate, 7838c2ecf20Sopenharmony_ci .round_rate = bcm2835_pll_round_rate, 7848c2ecf20Sopenharmony_ci .debug_init = bcm2835_pll_debug_init, 7858c2ecf20Sopenharmony_ci}; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_cistruct bcm2835_pll_divider { 7888c2ecf20Sopenharmony_ci struct clk_divider div; 7898c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman; 7908c2ecf20Sopenharmony_ci const struct bcm2835_pll_divider_data *data; 7918c2ecf20Sopenharmony_ci}; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_cistatic struct bcm2835_pll_divider * 7948c2ecf20Sopenharmony_cibcm2835_pll_divider_from_hw(struct clk_hw *hw) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci return container_of(hw, struct bcm2835_pll_divider, div.hw); 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cistatic int bcm2835_pll_divider_is_on(struct clk_hw *hw) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw); 8028c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman = divider->cprman; 8038c2ecf20Sopenharmony_ci const struct bcm2835_pll_divider_data *data = divider->data; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci return !(cprman_read(cprman, data->a2w_reg) & A2W_PLL_CHANNEL_DISABLE); 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_cistatic long bcm2835_pll_divider_round_rate(struct clk_hw *hw, 8098c2ecf20Sopenharmony_ci unsigned long rate, 8108c2ecf20Sopenharmony_ci unsigned long *parent_rate) 8118c2ecf20Sopenharmony_ci{ 8128c2ecf20Sopenharmony_ci return clk_divider_ops.round_rate(hw, rate, parent_rate); 8138c2ecf20Sopenharmony_ci} 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cistatic unsigned long bcm2835_pll_divider_get_rate(struct clk_hw *hw, 8168c2ecf20Sopenharmony_ci unsigned long parent_rate) 8178c2ecf20Sopenharmony_ci{ 8188c2ecf20Sopenharmony_ci return clk_divider_ops.recalc_rate(hw, parent_rate); 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_cistatic void bcm2835_pll_divider_off(struct clk_hw *hw) 8228c2ecf20Sopenharmony_ci{ 8238c2ecf20Sopenharmony_ci struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw); 8248c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman = divider->cprman; 8258c2ecf20Sopenharmony_ci const struct bcm2835_pll_divider_data *data = divider->data; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci spin_lock(&cprman->regs_lock); 8288c2ecf20Sopenharmony_ci cprman_write(cprman, data->cm_reg, 8298c2ecf20Sopenharmony_ci (cprman_read(cprman, data->cm_reg) & 8308c2ecf20Sopenharmony_ci ~data->load_mask) | data->hold_mask); 8318c2ecf20Sopenharmony_ci cprman_write(cprman, data->a2w_reg, 8328c2ecf20Sopenharmony_ci cprman_read(cprman, data->a2w_reg) | 8338c2ecf20Sopenharmony_ci A2W_PLL_CHANNEL_DISABLE); 8348c2ecf20Sopenharmony_ci spin_unlock(&cprman->regs_lock); 8358c2ecf20Sopenharmony_ci} 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_cistatic int bcm2835_pll_divider_on(struct clk_hw *hw) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw); 8408c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman = divider->cprman; 8418c2ecf20Sopenharmony_ci const struct bcm2835_pll_divider_data *data = divider->data; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci spin_lock(&cprman->regs_lock); 8448c2ecf20Sopenharmony_ci cprman_write(cprman, data->a2w_reg, 8458c2ecf20Sopenharmony_ci cprman_read(cprman, data->a2w_reg) & 8468c2ecf20Sopenharmony_ci ~A2W_PLL_CHANNEL_DISABLE); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci cprman_write(cprman, data->cm_reg, 8498c2ecf20Sopenharmony_ci cprman_read(cprman, data->cm_reg) & ~data->hold_mask); 8508c2ecf20Sopenharmony_ci spin_unlock(&cprman->regs_lock); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci return 0; 8538c2ecf20Sopenharmony_ci} 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_cistatic int bcm2835_pll_divider_set_rate(struct clk_hw *hw, 8568c2ecf20Sopenharmony_ci unsigned long rate, 8578c2ecf20Sopenharmony_ci unsigned long parent_rate) 8588c2ecf20Sopenharmony_ci{ 8598c2ecf20Sopenharmony_ci struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw); 8608c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman = divider->cprman; 8618c2ecf20Sopenharmony_ci const struct bcm2835_pll_divider_data *data = divider->data; 8628c2ecf20Sopenharmony_ci u32 cm, div, max_div = 1 << A2W_PLL_DIV_BITS; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci div = DIV_ROUND_UP_ULL(parent_rate, rate); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci div = min(div, max_div); 8678c2ecf20Sopenharmony_ci if (div == max_div) 8688c2ecf20Sopenharmony_ci div = 0; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci cprman_write(cprman, data->a2w_reg, div); 8718c2ecf20Sopenharmony_ci cm = cprman_read(cprman, data->cm_reg); 8728c2ecf20Sopenharmony_ci cprman_write(cprman, data->cm_reg, cm | data->load_mask); 8738c2ecf20Sopenharmony_ci cprman_write(cprman, data->cm_reg, cm & ~data->load_mask); 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci return 0; 8768c2ecf20Sopenharmony_ci} 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_cistatic void bcm2835_pll_divider_debug_init(struct clk_hw *hw, 8798c2ecf20Sopenharmony_ci struct dentry *dentry) 8808c2ecf20Sopenharmony_ci{ 8818c2ecf20Sopenharmony_ci struct bcm2835_pll_divider *divider = bcm2835_pll_divider_from_hw(hw); 8828c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman = divider->cprman; 8838c2ecf20Sopenharmony_ci const struct bcm2835_pll_divider_data *data = divider->data; 8848c2ecf20Sopenharmony_ci struct debugfs_reg32 *regs; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci regs = devm_kcalloc(cprman->dev, 7, sizeof(*regs), GFP_KERNEL); 8878c2ecf20Sopenharmony_ci if (!regs) 8888c2ecf20Sopenharmony_ci return; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci regs[0].name = "cm"; 8918c2ecf20Sopenharmony_ci regs[0].offset = data->cm_reg; 8928c2ecf20Sopenharmony_ci regs[1].name = "a2w"; 8938c2ecf20Sopenharmony_ci regs[1].offset = data->a2w_reg; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci bcm2835_debugfs_regset(cprman, 0, regs, 2, dentry); 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_cistatic const struct clk_ops bcm2835_pll_divider_clk_ops = { 8998c2ecf20Sopenharmony_ci .is_prepared = bcm2835_pll_divider_is_on, 9008c2ecf20Sopenharmony_ci .prepare = bcm2835_pll_divider_on, 9018c2ecf20Sopenharmony_ci .unprepare = bcm2835_pll_divider_off, 9028c2ecf20Sopenharmony_ci .recalc_rate = bcm2835_pll_divider_get_rate, 9038c2ecf20Sopenharmony_ci .set_rate = bcm2835_pll_divider_set_rate, 9048c2ecf20Sopenharmony_ci .round_rate = bcm2835_pll_divider_round_rate, 9058c2ecf20Sopenharmony_ci .debug_init = bcm2835_pll_divider_debug_init, 9068c2ecf20Sopenharmony_ci}; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci/* 9098c2ecf20Sopenharmony_ci * The CM dividers do fixed-point division, so we can't use the 9108c2ecf20Sopenharmony_ci * generic integer divider code like the PLL dividers do (and we can't 9118c2ecf20Sopenharmony_ci * fake it by having some fixed shifts preceding it in the clock tree, 9128c2ecf20Sopenharmony_ci * because we'd run out of bits in a 32-bit unsigned long). 9138c2ecf20Sopenharmony_ci */ 9148c2ecf20Sopenharmony_cistruct bcm2835_clock { 9158c2ecf20Sopenharmony_ci struct clk_hw hw; 9168c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman; 9178c2ecf20Sopenharmony_ci const struct bcm2835_clock_data *data; 9188c2ecf20Sopenharmony_ci}; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_cistatic struct bcm2835_clock *bcm2835_clock_from_hw(struct clk_hw *hw) 9218c2ecf20Sopenharmony_ci{ 9228c2ecf20Sopenharmony_ci return container_of(hw, struct bcm2835_clock, hw); 9238c2ecf20Sopenharmony_ci} 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_cistatic int bcm2835_clock_is_on(struct clk_hw *hw) 9268c2ecf20Sopenharmony_ci{ 9278c2ecf20Sopenharmony_ci struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); 9288c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman = clock->cprman; 9298c2ecf20Sopenharmony_ci const struct bcm2835_clock_data *data = clock->data; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci return (cprman_read(cprman, data->ctl_reg) & CM_ENABLE) != 0; 9328c2ecf20Sopenharmony_ci} 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_cistatic u32 bcm2835_clock_choose_div(struct clk_hw *hw, 9358c2ecf20Sopenharmony_ci unsigned long rate, 9368c2ecf20Sopenharmony_ci unsigned long parent_rate) 9378c2ecf20Sopenharmony_ci{ 9388c2ecf20Sopenharmony_ci struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); 9398c2ecf20Sopenharmony_ci const struct bcm2835_clock_data *data = clock->data; 9408c2ecf20Sopenharmony_ci u32 unused_frac_mask = 9418c2ecf20Sopenharmony_ci GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0) >> 1; 9428c2ecf20Sopenharmony_ci u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS; 9438c2ecf20Sopenharmony_ci u64 rem; 9448c2ecf20Sopenharmony_ci u32 div, mindiv, maxdiv; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci rem = do_div(temp, rate); 9478c2ecf20Sopenharmony_ci div = temp; 9488c2ecf20Sopenharmony_ci div &= ~unused_frac_mask; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci /* different clamping limits apply for a mash clock */ 9518c2ecf20Sopenharmony_ci if (data->is_mash_clock) { 9528c2ecf20Sopenharmony_ci /* clamp to min divider of 2 */ 9538c2ecf20Sopenharmony_ci mindiv = 2 << CM_DIV_FRAC_BITS; 9548c2ecf20Sopenharmony_ci /* clamp to the highest possible integer divider */ 9558c2ecf20Sopenharmony_ci maxdiv = (BIT(data->int_bits) - 1) << CM_DIV_FRAC_BITS; 9568c2ecf20Sopenharmony_ci } else { 9578c2ecf20Sopenharmony_ci /* clamp to min divider of 1 */ 9588c2ecf20Sopenharmony_ci mindiv = 1 << CM_DIV_FRAC_BITS; 9598c2ecf20Sopenharmony_ci /* clamp to the highest possible fractional divider */ 9608c2ecf20Sopenharmony_ci maxdiv = GENMASK(data->int_bits + CM_DIV_FRAC_BITS - 1, 9618c2ecf20Sopenharmony_ci CM_DIV_FRAC_BITS - data->frac_bits); 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci /* apply the clamping limits */ 9658c2ecf20Sopenharmony_ci div = max_t(u32, div, mindiv); 9668c2ecf20Sopenharmony_ci div = min_t(u32, div, maxdiv); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci return div; 9698c2ecf20Sopenharmony_ci} 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_cistatic unsigned long bcm2835_clock_rate_from_divisor(struct bcm2835_clock *clock, 9728c2ecf20Sopenharmony_ci unsigned long parent_rate, 9738c2ecf20Sopenharmony_ci u32 div) 9748c2ecf20Sopenharmony_ci{ 9758c2ecf20Sopenharmony_ci const struct bcm2835_clock_data *data = clock->data; 9768c2ecf20Sopenharmony_ci u64 temp; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci if (data->int_bits == 0 && data->frac_bits == 0) 9798c2ecf20Sopenharmony_ci return parent_rate; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci /* 9828c2ecf20Sopenharmony_ci * The divisor is a 12.12 fixed point field, but only some of 9838c2ecf20Sopenharmony_ci * the bits are populated in any given clock. 9848c2ecf20Sopenharmony_ci */ 9858c2ecf20Sopenharmony_ci div >>= CM_DIV_FRAC_BITS - data->frac_bits; 9868c2ecf20Sopenharmony_ci div &= (1 << (data->int_bits + data->frac_bits)) - 1; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci if (div == 0) 9898c2ecf20Sopenharmony_ci return 0; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci temp = (u64)parent_rate << data->frac_bits; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci do_div(temp, div); 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci return temp; 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistatic unsigned long bcm2835_clock_get_rate(struct clk_hw *hw, 9998c2ecf20Sopenharmony_ci unsigned long parent_rate) 10008c2ecf20Sopenharmony_ci{ 10018c2ecf20Sopenharmony_ci struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); 10028c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman = clock->cprman; 10038c2ecf20Sopenharmony_ci const struct bcm2835_clock_data *data = clock->data; 10048c2ecf20Sopenharmony_ci u32 div; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci if (data->int_bits == 0 && data->frac_bits == 0) 10078c2ecf20Sopenharmony_ci return parent_rate; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci div = cprman_read(cprman, data->div_reg); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci return bcm2835_clock_rate_from_divisor(clock, parent_rate, div); 10128c2ecf20Sopenharmony_ci} 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_cistatic void bcm2835_clock_wait_busy(struct bcm2835_clock *clock) 10158c2ecf20Sopenharmony_ci{ 10168c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman = clock->cprman; 10178c2ecf20Sopenharmony_ci const struct bcm2835_clock_data *data = clock->data; 10188c2ecf20Sopenharmony_ci ktime_t timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS); 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci while (cprman_read(cprman, data->ctl_reg) & CM_BUSY) { 10218c2ecf20Sopenharmony_ci if (ktime_after(ktime_get(), timeout)) { 10228c2ecf20Sopenharmony_ci dev_err(cprman->dev, "%s: couldn't lock PLL\n", 10238c2ecf20Sopenharmony_ci clk_hw_get_name(&clock->hw)); 10248c2ecf20Sopenharmony_ci return; 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci cpu_relax(); 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci} 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_cistatic void bcm2835_clock_off(struct clk_hw *hw) 10318c2ecf20Sopenharmony_ci{ 10328c2ecf20Sopenharmony_ci struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); 10338c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman = clock->cprman; 10348c2ecf20Sopenharmony_ci const struct bcm2835_clock_data *data = clock->data; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci spin_lock(&cprman->regs_lock); 10378c2ecf20Sopenharmony_ci cprman_write(cprman, data->ctl_reg, 10388c2ecf20Sopenharmony_ci cprman_read(cprman, data->ctl_reg) & ~CM_ENABLE); 10398c2ecf20Sopenharmony_ci spin_unlock(&cprman->regs_lock); 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci /* BUSY will remain high until the divider completes its cycle. */ 10428c2ecf20Sopenharmony_ci bcm2835_clock_wait_busy(clock); 10438c2ecf20Sopenharmony_ci} 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_cistatic int bcm2835_clock_on(struct clk_hw *hw) 10468c2ecf20Sopenharmony_ci{ 10478c2ecf20Sopenharmony_ci struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); 10488c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman = clock->cprman; 10498c2ecf20Sopenharmony_ci const struct bcm2835_clock_data *data = clock->data; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci spin_lock(&cprman->regs_lock); 10528c2ecf20Sopenharmony_ci cprman_write(cprman, data->ctl_reg, 10538c2ecf20Sopenharmony_ci cprman_read(cprman, data->ctl_reg) | 10548c2ecf20Sopenharmony_ci CM_ENABLE | 10558c2ecf20Sopenharmony_ci CM_GATE); 10568c2ecf20Sopenharmony_ci spin_unlock(&cprman->regs_lock); 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci /* Debug code to measure the clock once it's turned on to see 10598c2ecf20Sopenharmony_ci * if it's ticking at the rate we expect. 10608c2ecf20Sopenharmony_ci */ 10618c2ecf20Sopenharmony_ci if (data->tcnt_mux && false) { 10628c2ecf20Sopenharmony_ci dev_info(cprman->dev, 10638c2ecf20Sopenharmony_ci "clk %s: rate %ld, measure %ld\n", 10648c2ecf20Sopenharmony_ci data->name, 10658c2ecf20Sopenharmony_ci clk_hw_get_rate(hw), 10668c2ecf20Sopenharmony_ci bcm2835_measure_tcnt_mux(cprman, data->tcnt_mux)); 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci return 0; 10708c2ecf20Sopenharmony_ci} 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_cistatic int bcm2835_clock_set_rate(struct clk_hw *hw, 10738c2ecf20Sopenharmony_ci unsigned long rate, unsigned long parent_rate) 10748c2ecf20Sopenharmony_ci{ 10758c2ecf20Sopenharmony_ci struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); 10768c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman = clock->cprman; 10778c2ecf20Sopenharmony_ci const struct bcm2835_clock_data *data = clock->data; 10788c2ecf20Sopenharmony_ci u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate); 10798c2ecf20Sopenharmony_ci u32 ctl; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci spin_lock(&cprman->regs_lock); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci /* 10848c2ecf20Sopenharmony_ci * Setting up frac support 10858c2ecf20Sopenharmony_ci * 10868c2ecf20Sopenharmony_ci * In principle it is recommended to stop/start the clock first, 10878c2ecf20Sopenharmony_ci * but as we set CLK_SET_RATE_GATE during registration of the 10888c2ecf20Sopenharmony_ci * clock this requirement should be take care of by the 10898c2ecf20Sopenharmony_ci * clk-framework. 10908c2ecf20Sopenharmony_ci */ 10918c2ecf20Sopenharmony_ci ctl = cprman_read(cprman, data->ctl_reg) & ~CM_FRAC; 10928c2ecf20Sopenharmony_ci ctl |= (div & CM_DIV_FRAC_MASK) ? CM_FRAC : 0; 10938c2ecf20Sopenharmony_ci cprman_write(cprman, data->ctl_reg, ctl); 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci cprman_write(cprman, data->div_reg, div); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci spin_unlock(&cprman->regs_lock); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci return 0; 11008c2ecf20Sopenharmony_ci} 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_cistatic bool 11038c2ecf20Sopenharmony_cibcm2835_clk_is_pllc(struct clk_hw *hw) 11048c2ecf20Sopenharmony_ci{ 11058c2ecf20Sopenharmony_ci if (!hw) 11068c2ecf20Sopenharmony_ci return false; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci return strncmp(clk_hw_get_name(hw), "pllc", 4) == 0; 11098c2ecf20Sopenharmony_ci} 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_cistatic unsigned long bcm2835_clock_choose_div_and_prate(struct clk_hw *hw, 11128c2ecf20Sopenharmony_ci int parent_idx, 11138c2ecf20Sopenharmony_ci unsigned long rate, 11148c2ecf20Sopenharmony_ci u32 *div, 11158c2ecf20Sopenharmony_ci unsigned long *prate, 11168c2ecf20Sopenharmony_ci unsigned long *avgrate) 11178c2ecf20Sopenharmony_ci{ 11188c2ecf20Sopenharmony_ci struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); 11198c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman = clock->cprman; 11208c2ecf20Sopenharmony_ci const struct bcm2835_clock_data *data = clock->data; 11218c2ecf20Sopenharmony_ci unsigned long best_rate = 0; 11228c2ecf20Sopenharmony_ci u32 curdiv, mindiv, maxdiv; 11238c2ecf20Sopenharmony_ci struct clk_hw *parent; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci parent = clk_hw_get_parent_by_index(hw, parent_idx); 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci if (!(BIT(parent_idx) & data->set_rate_parent)) { 11288c2ecf20Sopenharmony_ci *prate = clk_hw_get_rate(parent); 11298c2ecf20Sopenharmony_ci *div = bcm2835_clock_choose_div(hw, rate, *prate); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci *avgrate = bcm2835_clock_rate_from_divisor(clock, *prate, *div); 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci if (data->low_jitter && (*div & CM_DIV_FRAC_MASK)) { 11348c2ecf20Sopenharmony_ci unsigned long high, low; 11358c2ecf20Sopenharmony_ci u32 int_div = *div & ~CM_DIV_FRAC_MASK; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci high = bcm2835_clock_rate_from_divisor(clock, *prate, 11388c2ecf20Sopenharmony_ci int_div); 11398c2ecf20Sopenharmony_ci int_div += CM_DIV_FRAC_MASK + 1; 11408c2ecf20Sopenharmony_ci low = bcm2835_clock_rate_from_divisor(clock, *prate, 11418c2ecf20Sopenharmony_ci int_div); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci /* 11448c2ecf20Sopenharmony_ci * Return a value which is the maximum deviation 11458c2ecf20Sopenharmony_ci * below the ideal rate, for use as a metric. 11468c2ecf20Sopenharmony_ci */ 11478c2ecf20Sopenharmony_ci return *avgrate - max(*avgrate - low, high - *avgrate); 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci return *avgrate; 11508c2ecf20Sopenharmony_ci } 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci if (data->frac_bits) 11538c2ecf20Sopenharmony_ci dev_warn(cprman->dev, 11548c2ecf20Sopenharmony_ci "frac bits are not used when propagating rate change"); 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci /* clamp to min divider of 2 if we're dealing with a mash clock */ 11578c2ecf20Sopenharmony_ci mindiv = data->is_mash_clock ? 2 : 1; 11588c2ecf20Sopenharmony_ci maxdiv = BIT(data->int_bits) - 1; 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci /* TODO: Be smart, and only test a subset of the available divisors. */ 11618c2ecf20Sopenharmony_ci for (curdiv = mindiv; curdiv <= maxdiv; curdiv++) { 11628c2ecf20Sopenharmony_ci unsigned long tmp_rate; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci tmp_rate = clk_hw_round_rate(parent, rate * curdiv); 11658c2ecf20Sopenharmony_ci tmp_rate /= curdiv; 11668c2ecf20Sopenharmony_ci if (curdiv == mindiv || 11678c2ecf20Sopenharmony_ci (tmp_rate > best_rate && tmp_rate <= rate)) 11688c2ecf20Sopenharmony_ci best_rate = tmp_rate; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci if (best_rate == rate) 11718c2ecf20Sopenharmony_ci break; 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci *div = curdiv << CM_DIV_FRAC_BITS; 11758c2ecf20Sopenharmony_ci *prate = curdiv * best_rate; 11768c2ecf20Sopenharmony_ci *avgrate = best_rate; 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci return best_rate; 11798c2ecf20Sopenharmony_ci} 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_cistatic int bcm2835_clock_determine_rate(struct clk_hw *hw, 11828c2ecf20Sopenharmony_ci struct clk_rate_request *req) 11838c2ecf20Sopenharmony_ci{ 11848c2ecf20Sopenharmony_ci struct clk_hw *parent, *best_parent = NULL; 11858c2ecf20Sopenharmony_ci bool current_parent_is_pllc; 11868c2ecf20Sopenharmony_ci unsigned long rate, best_rate = 0; 11878c2ecf20Sopenharmony_ci unsigned long prate, best_prate = 0; 11888c2ecf20Sopenharmony_ci unsigned long avgrate, best_avgrate = 0; 11898c2ecf20Sopenharmony_ci size_t i; 11908c2ecf20Sopenharmony_ci u32 div; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci current_parent_is_pllc = bcm2835_clk_is_pllc(clk_hw_get_parent(hw)); 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci /* 11958c2ecf20Sopenharmony_ci * Select parent clock that results in the closest but lower rate 11968c2ecf20Sopenharmony_ci */ 11978c2ecf20Sopenharmony_ci for (i = 0; i < clk_hw_get_num_parents(hw); ++i) { 11988c2ecf20Sopenharmony_ci parent = clk_hw_get_parent_by_index(hw, i); 11998c2ecf20Sopenharmony_ci if (!parent) 12008c2ecf20Sopenharmony_ci continue; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci /* 12038c2ecf20Sopenharmony_ci * Don't choose a PLLC-derived clock as our parent 12048c2ecf20Sopenharmony_ci * unless it had been manually set that way. PLLC's 12058c2ecf20Sopenharmony_ci * frequency gets adjusted by the firmware due to 12068c2ecf20Sopenharmony_ci * over-temp or under-voltage conditions, without 12078c2ecf20Sopenharmony_ci * prior notification to our clock consumer. 12088c2ecf20Sopenharmony_ci */ 12098c2ecf20Sopenharmony_ci if (bcm2835_clk_is_pllc(parent) && !current_parent_is_pllc) 12108c2ecf20Sopenharmony_ci continue; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci rate = bcm2835_clock_choose_div_and_prate(hw, i, req->rate, 12138c2ecf20Sopenharmony_ci &div, &prate, 12148c2ecf20Sopenharmony_ci &avgrate); 12158c2ecf20Sopenharmony_ci if (abs(req->rate - rate) < abs(req->rate - best_rate)) { 12168c2ecf20Sopenharmony_ci best_parent = parent; 12178c2ecf20Sopenharmony_ci best_prate = prate; 12188c2ecf20Sopenharmony_ci best_rate = rate; 12198c2ecf20Sopenharmony_ci best_avgrate = avgrate; 12208c2ecf20Sopenharmony_ci } 12218c2ecf20Sopenharmony_ci } 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci if (!best_parent) 12248c2ecf20Sopenharmony_ci return -EINVAL; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci req->best_parent_hw = best_parent; 12278c2ecf20Sopenharmony_ci req->best_parent_rate = best_prate; 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci req->rate = best_avgrate; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci return 0; 12328c2ecf20Sopenharmony_ci} 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_cistatic int bcm2835_clock_set_parent(struct clk_hw *hw, u8 index) 12358c2ecf20Sopenharmony_ci{ 12368c2ecf20Sopenharmony_ci struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); 12378c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman = clock->cprman; 12388c2ecf20Sopenharmony_ci const struct bcm2835_clock_data *data = clock->data; 12398c2ecf20Sopenharmony_ci u8 src = (index << CM_SRC_SHIFT) & CM_SRC_MASK; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci cprman_write(cprman, data->ctl_reg, src); 12428c2ecf20Sopenharmony_ci return 0; 12438c2ecf20Sopenharmony_ci} 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_cistatic u8 bcm2835_clock_get_parent(struct clk_hw *hw) 12468c2ecf20Sopenharmony_ci{ 12478c2ecf20Sopenharmony_ci struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); 12488c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman = clock->cprman; 12498c2ecf20Sopenharmony_ci const struct bcm2835_clock_data *data = clock->data; 12508c2ecf20Sopenharmony_ci u32 src = cprman_read(cprman, data->ctl_reg); 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci return (src & CM_SRC_MASK) >> CM_SRC_SHIFT; 12538c2ecf20Sopenharmony_ci} 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_cistatic const struct debugfs_reg32 bcm2835_debugfs_clock_reg32[] = { 12568c2ecf20Sopenharmony_ci { 12578c2ecf20Sopenharmony_ci .name = "ctl", 12588c2ecf20Sopenharmony_ci .offset = 0, 12598c2ecf20Sopenharmony_ci }, 12608c2ecf20Sopenharmony_ci { 12618c2ecf20Sopenharmony_ci .name = "div", 12628c2ecf20Sopenharmony_ci .offset = 4, 12638c2ecf20Sopenharmony_ci }, 12648c2ecf20Sopenharmony_ci}; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_cistatic void bcm2835_clock_debug_init(struct clk_hw *hw, 12678c2ecf20Sopenharmony_ci struct dentry *dentry) 12688c2ecf20Sopenharmony_ci{ 12698c2ecf20Sopenharmony_ci struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); 12708c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman = clock->cprman; 12718c2ecf20Sopenharmony_ci const struct bcm2835_clock_data *data = clock->data; 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci bcm2835_debugfs_regset(cprman, data->ctl_reg, 12748c2ecf20Sopenharmony_ci bcm2835_debugfs_clock_reg32, 12758c2ecf20Sopenharmony_ci ARRAY_SIZE(bcm2835_debugfs_clock_reg32), 12768c2ecf20Sopenharmony_ci dentry); 12778c2ecf20Sopenharmony_ci} 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_cistatic const struct clk_ops bcm2835_clock_clk_ops = { 12808c2ecf20Sopenharmony_ci .is_prepared = bcm2835_clock_is_on, 12818c2ecf20Sopenharmony_ci .prepare = bcm2835_clock_on, 12828c2ecf20Sopenharmony_ci .unprepare = bcm2835_clock_off, 12838c2ecf20Sopenharmony_ci .recalc_rate = bcm2835_clock_get_rate, 12848c2ecf20Sopenharmony_ci .set_rate = bcm2835_clock_set_rate, 12858c2ecf20Sopenharmony_ci .determine_rate = bcm2835_clock_determine_rate, 12868c2ecf20Sopenharmony_ci .set_parent = bcm2835_clock_set_parent, 12878c2ecf20Sopenharmony_ci .get_parent = bcm2835_clock_get_parent, 12888c2ecf20Sopenharmony_ci .debug_init = bcm2835_clock_debug_init, 12898c2ecf20Sopenharmony_ci}; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_cistatic int bcm2835_vpu_clock_is_on(struct clk_hw *hw) 12928c2ecf20Sopenharmony_ci{ 12938c2ecf20Sopenharmony_ci return true; 12948c2ecf20Sopenharmony_ci} 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci/* 12978c2ecf20Sopenharmony_ci * The VPU clock can never be disabled (it doesn't have an ENABLE 12988c2ecf20Sopenharmony_ci * bit), so it gets its own set of clock ops. 12998c2ecf20Sopenharmony_ci */ 13008c2ecf20Sopenharmony_cistatic const struct clk_ops bcm2835_vpu_clock_clk_ops = { 13018c2ecf20Sopenharmony_ci .is_prepared = bcm2835_vpu_clock_is_on, 13028c2ecf20Sopenharmony_ci .recalc_rate = bcm2835_clock_get_rate, 13038c2ecf20Sopenharmony_ci .set_rate = bcm2835_clock_set_rate, 13048c2ecf20Sopenharmony_ci .determine_rate = bcm2835_clock_determine_rate, 13058c2ecf20Sopenharmony_ci .set_parent = bcm2835_clock_set_parent, 13068c2ecf20Sopenharmony_ci .get_parent = bcm2835_clock_get_parent, 13078c2ecf20Sopenharmony_ci .debug_init = bcm2835_clock_debug_init, 13088c2ecf20Sopenharmony_ci}; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_cistatic struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman, 13118c2ecf20Sopenharmony_ci const void *data) 13128c2ecf20Sopenharmony_ci{ 13138c2ecf20Sopenharmony_ci const struct bcm2835_pll_data *pll_data = data; 13148c2ecf20Sopenharmony_ci struct bcm2835_pll *pll; 13158c2ecf20Sopenharmony_ci struct clk_init_data init; 13168c2ecf20Sopenharmony_ci int ret; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci memset(&init, 0, sizeof(init)); 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci /* All of the PLLs derive from the external oscillator. */ 13218c2ecf20Sopenharmony_ci init.parent_names = &cprman->real_parent_names[0]; 13228c2ecf20Sopenharmony_ci init.num_parents = 1; 13238c2ecf20Sopenharmony_ci init.name = pll_data->name; 13248c2ecf20Sopenharmony_ci init.ops = &bcm2835_pll_clk_ops; 13258c2ecf20Sopenharmony_ci init.flags = pll_data->flags | CLK_IGNORE_UNUSED; 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci pll = kzalloc(sizeof(*pll), GFP_KERNEL); 13288c2ecf20Sopenharmony_ci if (!pll) 13298c2ecf20Sopenharmony_ci return NULL; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci pll->cprman = cprman; 13328c2ecf20Sopenharmony_ci pll->data = pll_data; 13338c2ecf20Sopenharmony_ci pll->hw.init = &init; 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci ret = devm_clk_hw_register(cprman->dev, &pll->hw); 13368c2ecf20Sopenharmony_ci if (ret) { 13378c2ecf20Sopenharmony_ci kfree(pll); 13388c2ecf20Sopenharmony_ci return NULL; 13398c2ecf20Sopenharmony_ci } 13408c2ecf20Sopenharmony_ci return &pll->hw; 13418c2ecf20Sopenharmony_ci} 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_cistatic struct clk_hw * 13448c2ecf20Sopenharmony_cibcm2835_register_pll_divider(struct bcm2835_cprman *cprman, 13458c2ecf20Sopenharmony_ci const void *data) 13468c2ecf20Sopenharmony_ci{ 13478c2ecf20Sopenharmony_ci const struct bcm2835_pll_divider_data *divider_data = data; 13488c2ecf20Sopenharmony_ci struct bcm2835_pll_divider *divider; 13498c2ecf20Sopenharmony_ci struct clk_init_data init; 13508c2ecf20Sopenharmony_ci const char *divider_name; 13518c2ecf20Sopenharmony_ci int ret; 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci if (divider_data->fixed_divider != 1) { 13548c2ecf20Sopenharmony_ci divider_name = devm_kasprintf(cprman->dev, GFP_KERNEL, 13558c2ecf20Sopenharmony_ci "%s_prediv", divider_data->name); 13568c2ecf20Sopenharmony_ci if (!divider_name) 13578c2ecf20Sopenharmony_ci return NULL; 13588c2ecf20Sopenharmony_ci } else { 13598c2ecf20Sopenharmony_ci divider_name = divider_data->name; 13608c2ecf20Sopenharmony_ci } 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci memset(&init, 0, sizeof(init)); 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci init.parent_names = ÷r_data->source_pll; 13658c2ecf20Sopenharmony_ci init.num_parents = 1; 13668c2ecf20Sopenharmony_ci init.name = divider_name; 13678c2ecf20Sopenharmony_ci init.ops = &bcm2835_pll_divider_clk_ops; 13688c2ecf20Sopenharmony_ci init.flags = divider_data->flags | CLK_IGNORE_UNUSED; 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci divider = devm_kzalloc(cprman->dev, sizeof(*divider), GFP_KERNEL); 13718c2ecf20Sopenharmony_ci if (!divider) 13728c2ecf20Sopenharmony_ci return NULL; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci divider->div.reg = cprman->regs + divider_data->a2w_reg; 13758c2ecf20Sopenharmony_ci divider->div.shift = A2W_PLL_DIV_SHIFT; 13768c2ecf20Sopenharmony_ci divider->div.width = A2W_PLL_DIV_BITS; 13778c2ecf20Sopenharmony_ci divider->div.flags = CLK_DIVIDER_MAX_AT_ZERO; 13788c2ecf20Sopenharmony_ci divider->div.lock = &cprman->regs_lock; 13798c2ecf20Sopenharmony_ci divider->div.hw.init = &init; 13808c2ecf20Sopenharmony_ci divider->div.table = NULL; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci divider->cprman = cprman; 13838c2ecf20Sopenharmony_ci divider->data = divider_data; 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci ret = devm_clk_hw_register(cprman->dev, ÷r->div.hw); 13868c2ecf20Sopenharmony_ci if (ret) 13878c2ecf20Sopenharmony_ci return ERR_PTR(ret); 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci /* 13908c2ecf20Sopenharmony_ci * PLLH's channels have a fixed divide by 10 afterwards, which 13918c2ecf20Sopenharmony_ci * is what our consumers are actually using. 13928c2ecf20Sopenharmony_ci */ 13938c2ecf20Sopenharmony_ci if (divider_data->fixed_divider != 1) { 13948c2ecf20Sopenharmony_ci return clk_hw_register_fixed_factor(cprman->dev, 13958c2ecf20Sopenharmony_ci divider_data->name, 13968c2ecf20Sopenharmony_ci divider_name, 13978c2ecf20Sopenharmony_ci CLK_SET_RATE_PARENT, 13988c2ecf20Sopenharmony_ci 1, 13998c2ecf20Sopenharmony_ci divider_data->fixed_divider); 14008c2ecf20Sopenharmony_ci } 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci return ÷r->div.hw; 14038c2ecf20Sopenharmony_ci} 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_cistatic struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman, 14068c2ecf20Sopenharmony_ci const void *data) 14078c2ecf20Sopenharmony_ci{ 14088c2ecf20Sopenharmony_ci const struct bcm2835_clock_data *clock_data = data; 14098c2ecf20Sopenharmony_ci struct bcm2835_clock *clock; 14108c2ecf20Sopenharmony_ci struct clk_init_data init; 14118c2ecf20Sopenharmony_ci const char *parents[1 << CM_SRC_BITS]; 14128c2ecf20Sopenharmony_ci size_t i; 14138c2ecf20Sopenharmony_ci int ret; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci /* 14168c2ecf20Sopenharmony_ci * Replace our strings referencing parent clocks with the 14178c2ecf20Sopenharmony_ci * actual clock-output-name of the parent. 14188c2ecf20Sopenharmony_ci */ 14198c2ecf20Sopenharmony_ci for (i = 0; i < clock_data->num_mux_parents; i++) { 14208c2ecf20Sopenharmony_ci parents[i] = clock_data->parents[i]; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci ret = match_string(cprman_parent_names, 14238c2ecf20Sopenharmony_ci ARRAY_SIZE(cprman_parent_names), 14248c2ecf20Sopenharmony_ci parents[i]); 14258c2ecf20Sopenharmony_ci if (ret >= 0) 14268c2ecf20Sopenharmony_ci parents[i] = cprman->real_parent_names[ret]; 14278c2ecf20Sopenharmony_ci } 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci memset(&init, 0, sizeof(init)); 14308c2ecf20Sopenharmony_ci init.parent_names = parents; 14318c2ecf20Sopenharmony_ci init.num_parents = clock_data->num_mux_parents; 14328c2ecf20Sopenharmony_ci init.name = clock_data->name; 14338c2ecf20Sopenharmony_ci init.flags = clock_data->flags | CLK_IGNORE_UNUSED; 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci /* 14368c2ecf20Sopenharmony_ci * Pass the CLK_SET_RATE_PARENT flag if we are allowed to propagate 14378c2ecf20Sopenharmony_ci * rate changes on at least of the parents. 14388c2ecf20Sopenharmony_ci */ 14398c2ecf20Sopenharmony_ci if (clock_data->set_rate_parent) 14408c2ecf20Sopenharmony_ci init.flags |= CLK_SET_RATE_PARENT; 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci if (clock_data->is_vpu_clock) { 14438c2ecf20Sopenharmony_ci init.ops = &bcm2835_vpu_clock_clk_ops; 14448c2ecf20Sopenharmony_ci } else { 14458c2ecf20Sopenharmony_ci init.ops = &bcm2835_clock_clk_ops; 14468c2ecf20Sopenharmony_ci init.flags |= CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci /* If the clock wasn't actually enabled at boot, it's not 14498c2ecf20Sopenharmony_ci * critical. 14508c2ecf20Sopenharmony_ci */ 14518c2ecf20Sopenharmony_ci if (!(cprman_read(cprman, clock_data->ctl_reg) & CM_ENABLE)) 14528c2ecf20Sopenharmony_ci init.flags &= ~CLK_IS_CRITICAL; 14538c2ecf20Sopenharmony_ci } 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci clock = devm_kzalloc(cprman->dev, sizeof(*clock), GFP_KERNEL); 14568c2ecf20Sopenharmony_ci if (!clock) 14578c2ecf20Sopenharmony_ci return NULL; 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci clock->cprman = cprman; 14608c2ecf20Sopenharmony_ci clock->data = clock_data; 14618c2ecf20Sopenharmony_ci clock->hw.init = &init; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci ret = devm_clk_hw_register(cprman->dev, &clock->hw); 14648c2ecf20Sopenharmony_ci if (ret) 14658c2ecf20Sopenharmony_ci return ERR_PTR(ret); 14668c2ecf20Sopenharmony_ci return &clock->hw; 14678c2ecf20Sopenharmony_ci} 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_cistatic struct clk_hw *bcm2835_register_gate(struct bcm2835_cprman *cprman, 14708c2ecf20Sopenharmony_ci const void *data) 14718c2ecf20Sopenharmony_ci{ 14728c2ecf20Sopenharmony_ci const struct bcm2835_gate_data *gate_data = data; 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci return clk_hw_register_gate(cprman->dev, gate_data->name, 14758c2ecf20Sopenharmony_ci gate_data->parent, 14768c2ecf20Sopenharmony_ci CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, 14778c2ecf20Sopenharmony_ci cprman->regs + gate_data->ctl_reg, 14788c2ecf20Sopenharmony_ci CM_GATE_BIT, 0, &cprman->regs_lock); 14798c2ecf20Sopenharmony_ci} 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_cistruct bcm2835_clk_desc { 14828c2ecf20Sopenharmony_ci struct clk_hw *(*clk_register)(struct bcm2835_cprman *cprman, 14838c2ecf20Sopenharmony_ci const void *data); 14848c2ecf20Sopenharmony_ci unsigned int supported; 14858c2ecf20Sopenharmony_ci const void *data; 14868c2ecf20Sopenharmony_ci}; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci/* assignment helper macros for different clock types */ 14898c2ecf20Sopenharmony_ci#define _REGISTER(f, s, ...) { .clk_register = f, \ 14908c2ecf20Sopenharmony_ci .supported = s, \ 14918c2ecf20Sopenharmony_ci .data = __VA_ARGS__ } 14928c2ecf20Sopenharmony_ci#define REGISTER_PLL(s, ...) _REGISTER(&bcm2835_register_pll, \ 14938c2ecf20Sopenharmony_ci s, \ 14948c2ecf20Sopenharmony_ci &(struct bcm2835_pll_data) \ 14958c2ecf20Sopenharmony_ci {__VA_ARGS__}) 14968c2ecf20Sopenharmony_ci#define REGISTER_PLL_DIV(s, ...) _REGISTER(&bcm2835_register_pll_divider, \ 14978c2ecf20Sopenharmony_ci s, \ 14988c2ecf20Sopenharmony_ci &(struct bcm2835_pll_divider_data) \ 14998c2ecf20Sopenharmony_ci {__VA_ARGS__}) 15008c2ecf20Sopenharmony_ci#define REGISTER_CLK(s, ...) _REGISTER(&bcm2835_register_clock, \ 15018c2ecf20Sopenharmony_ci s, \ 15028c2ecf20Sopenharmony_ci &(struct bcm2835_clock_data) \ 15038c2ecf20Sopenharmony_ci {__VA_ARGS__}) 15048c2ecf20Sopenharmony_ci#define REGISTER_GATE(s, ...) _REGISTER(&bcm2835_register_gate, \ 15058c2ecf20Sopenharmony_ci s, \ 15068c2ecf20Sopenharmony_ci &(struct bcm2835_gate_data) \ 15078c2ecf20Sopenharmony_ci {__VA_ARGS__}) 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci/* parent mux arrays plus helper macros */ 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci/* main oscillator parent mux */ 15128c2ecf20Sopenharmony_cistatic const char *const bcm2835_clock_osc_parents[] = { 15138c2ecf20Sopenharmony_ci "gnd", 15148c2ecf20Sopenharmony_ci "xosc", 15158c2ecf20Sopenharmony_ci "testdebug0", 15168c2ecf20Sopenharmony_ci "testdebug1" 15178c2ecf20Sopenharmony_ci}; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci#define REGISTER_OSC_CLK(s, ...) REGISTER_CLK( \ 15208c2ecf20Sopenharmony_ci s, \ 15218c2ecf20Sopenharmony_ci .num_mux_parents = ARRAY_SIZE(bcm2835_clock_osc_parents), \ 15228c2ecf20Sopenharmony_ci .parents = bcm2835_clock_osc_parents, \ 15238c2ecf20Sopenharmony_ci __VA_ARGS__) 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci/* main peripherial parent mux */ 15268c2ecf20Sopenharmony_cistatic const char *const bcm2835_clock_per_parents[] = { 15278c2ecf20Sopenharmony_ci "gnd", 15288c2ecf20Sopenharmony_ci "xosc", 15298c2ecf20Sopenharmony_ci "testdebug0", 15308c2ecf20Sopenharmony_ci "testdebug1", 15318c2ecf20Sopenharmony_ci "plla_per", 15328c2ecf20Sopenharmony_ci "pllc_per", 15338c2ecf20Sopenharmony_ci "plld_per", 15348c2ecf20Sopenharmony_ci "pllh_aux", 15358c2ecf20Sopenharmony_ci}; 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci#define REGISTER_PER_CLK(s, ...) REGISTER_CLK( \ 15388c2ecf20Sopenharmony_ci s, \ 15398c2ecf20Sopenharmony_ci .num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents), \ 15408c2ecf20Sopenharmony_ci .parents = bcm2835_clock_per_parents, \ 15418c2ecf20Sopenharmony_ci __VA_ARGS__) 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci/* 15448c2ecf20Sopenharmony_ci * Restrict clock sources for the PCM peripheral to the oscillator and 15458c2ecf20Sopenharmony_ci * PLLD_PER because other source may have varying rates or be switched 15468c2ecf20Sopenharmony_ci * off. 15478c2ecf20Sopenharmony_ci * 15488c2ecf20Sopenharmony_ci * Prevent other sources from being selected by replacing their names in 15498c2ecf20Sopenharmony_ci * the list of potential parents with dummy entries (entry index is 15508c2ecf20Sopenharmony_ci * significant). 15518c2ecf20Sopenharmony_ci */ 15528c2ecf20Sopenharmony_cistatic const char *const bcm2835_pcm_per_parents[] = { 15538c2ecf20Sopenharmony_ci "-", 15548c2ecf20Sopenharmony_ci "xosc", 15558c2ecf20Sopenharmony_ci "-", 15568c2ecf20Sopenharmony_ci "-", 15578c2ecf20Sopenharmony_ci "-", 15588c2ecf20Sopenharmony_ci "-", 15598c2ecf20Sopenharmony_ci "plld_per", 15608c2ecf20Sopenharmony_ci "-", 15618c2ecf20Sopenharmony_ci}; 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci#define REGISTER_PCM_CLK(s, ...) REGISTER_CLK( \ 15648c2ecf20Sopenharmony_ci s, \ 15658c2ecf20Sopenharmony_ci .num_mux_parents = ARRAY_SIZE(bcm2835_pcm_per_parents), \ 15668c2ecf20Sopenharmony_ci .parents = bcm2835_pcm_per_parents, \ 15678c2ecf20Sopenharmony_ci __VA_ARGS__) 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci/* main vpu parent mux */ 15708c2ecf20Sopenharmony_cistatic const char *const bcm2835_clock_vpu_parents[] = { 15718c2ecf20Sopenharmony_ci "gnd", 15728c2ecf20Sopenharmony_ci "xosc", 15738c2ecf20Sopenharmony_ci "testdebug0", 15748c2ecf20Sopenharmony_ci "testdebug1", 15758c2ecf20Sopenharmony_ci "plla_core", 15768c2ecf20Sopenharmony_ci "pllc_core0", 15778c2ecf20Sopenharmony_ci "plld_core", 15788c2ecf20Sopenharmony_ci "pllh_aux", 15798c2ecf20Sopenharmony_ci "pllc_core1", 15808c2ecf20Sopenharmony_ci "pllc_core2", 15818c2ecf20Sopenharmony_ci}; 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci#define REGISTER_VPU_CLK(s, ...) REGISTER_CLK( \ 15848c2ecf20Sopenharmony_ci s, \ 15858c2ecf20Sopenharmony_ci .num_mux_parents = ARRAY_SIZE(bcm2835_clock_vpu_parents), \ 15868c2ecf20Sopenharmony_ci .parents = bcm2835_clock_vpu_parents, \ 15878c2ecf20Sopenharmony_ci __VA_ARGS__) 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci/* 15908c2ecf20Sopenharmony_ci * DSI parent clocks. The DSI byte/DDR/DDR2 clocks come from the DSI 15918c2ecf20Sopenharmony_ci * analog PHY. The _inv variants are generated internally to cprman, 15928c2ecf20Sopenharmony_ci * but we don't use them so they aren't hooked up. 15938c2ecf20Sopenharmony_ci */ 15948c2ecf20Sopenharmony_cistatic const char *const bcm2835_clock_dsi0_parents[] = { 15958c2ecf20Sopenharmony_ci "gnd", 15968c2ecf20Sopenharmony_ci "xosc", 15978c2ecf20Sopenharmony_ci "testdebug0", 15988c2ecf20Sopenharmony_ci "testdebug1", 15998c2ecf20Sopenharmony_ci "dsi0_ddr", 16008c2ecf20Sopenharmony_ci "dsi0_ddr_inv", 16018c2ecf20Sopenharmony_ci "dsi0_ddr2", 16028c2ecf20Sopenharmony_ci "dsi0_ddr2_inv", 16038c2ecf20Sopenharmony_ci "dsi0_byte", 16048c2ecf20Sopenharmony_ci "dsi0_byte_inv", 16058c2ecf20Sopenharmony_ci}; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_cistatic const char *const bcm2835_clock_dsi1_parents[] = { 16088c2ecf20Sopenharmony_ci "gnd", 16098c2ecf20Sopenharmony_ci "xosc", 16108c2ecf20Sopenharmony_ci "testdebug0", 16118c2ecf20Sopenharmony_ci "testdebug1", 16128c2ecf20Sopenharmony_ci "dsi1_ddr", 16138c2ecf20Sopenharmony_ci "dsi1_ddr_inv", 16148c2ecf20Sopenharmony_ci "dsi1_ddr2", 16158c2ecf20Sopenharmony_ci "dsi1_ddr2_inv", 16168c2ecf20Sopenharmony_ci "dsi1_byte", 16178c2ecf20Sopenharmony_ci "dsi1_byte_inv", 16188c2ecf20Sopenharmony_ci}; 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci#define REGISTER_DSI0_CLK(s, ...) REGISTER_CLK( \ 16218c2ecf20Sopenharmony_ci s, \ 16228c2ecf20Sopenharmony_ci .num_mux_parents = ARRAY_SIZE(bcm2835_clock_dsi0_parents), \ 16238c2ecf20Sopenharmony_ci .parents = bcm2835_clock_dsi0_parents, \ 16248c2ecf20Sopenharmony_ci __VA_ARGS__) 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci#define REGISTER_DSI1_CLK(s, ...) REGISTER_CLK( \ 16278c2ecf20Sopenharmony_ci s, \ 16288c2ecf20Sopenharmony_ci .num_mux_parents = ARRAY_SIZE(bcm2835_clock_dsi1_parents), \ 16298c2ecf20Sopenharmony_ci .parents = bcm2835_clock_dsi1_parents, \ 16308c2ecf20Sopenharmony_ci __VA_ARGS__) 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci/* 16338c2ecf20Sopenharmony_ci * the real definition of all the pll, pll_dividers and clocks 16348c2ecf20Sopenharmony_ci * these make use of the above REGISTER_* macros 16358c2ecf20Sopenharmony_ci */ 16368c2ecf20Sopenharmony_cistatic const struct bcm2835_clk_desc clk_desc_array[] = { 16378c2ecf20Sopenharmony_ci /* the PLL + PLL dividers */ 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci /* 16408c2ecf20Sopenharmony_ci * PLLA is the auxiliary PLL, used to drive the CCP2 16418c2ecf20Sopenharmony_ci * (Compact Camera Port 2) transmitter clock. 16428c2ecf20Sopenharmony_ci * 16438c2ecf20Sopenharmony_ci * It is in the PX LDO power domain, which is on when the 16448c2ecf20Sopenharmony_ci * AUDIO domain is on. 16458c2ecf20Sopenharmony_ci */ 16468c2ecf20Sopenharmony_ci [BCM2835_PLLA] = REGISTER_PLL( 16478c2ecf20Sopenharmony_ci SOC_ALL, 16488c2ecf20Sopenharmony_ci .name = "plla", 16498c2ecf20Sopenharmony_ci .cm_ctrl_reg = CM_PLLA, 16508c2ecf20Sopenharmony_ci .a2w_ctrl_reg = A2W_PLLA_CTRL, 16518c2ecf20Sopenharmony_ci .frac_reg = A2W_PLLA_FRAC, 16528c2ecf20Sopenharmony_ci .ana_reg_base = A2W_PLLA_ANA0, 16538c2ecf20Sopenharmony_ci .reference_enable_mask = A2W_XOSC_CTRL_PLLA_ENABLE, 16548c2ecf20Sopenharmony_ci .lock_mask = CM_LOCK_FLOCKA, 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci .ana = &bcm2835_ana_default, 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci .min_rate = 600000000u, 16598c2ecf20Sopenharmony_ci .max_rate = 2400000000u, 16608c2ecf20Sopenharmony_ci .max_fb_rate = BCM2835_MAX_FB_RATE), 16618c2ecf20Sopenharmony_ci [BCM2835_PLLA_CORE] = REGISTER_PLL_DIV( 16628c2ecf20Sopenharmony_ci SOC_ALL, 16638c2ecf20Sopenharmony_ci .name = "plla_core", 16648c2ecf20Sopenharmony_ci .source_pll = "plla", 16658c2ecf20Sopenharmony_ci .cm_reg = CM_PLLA, 16668c2ecf20Sopenharmony_ci .a2w_reg = A2W_PLLA_CORE, 16678c2ecf20Sopenharmony_ci .load_mask = CM_PLLA_LOADCORE, 16688c2ecf20Sopenharmony_ci .hold_mask = CM_PLLA_HOLDCORE, 16698c2ecf20Sopenharmony_ci .fixed_divider = 1, 16708c2ecf20Sopenharmony_ci .flags = CLK_SET_RATE_PARENT), 16718c2ecf20Sopenharmony_ci [BCM2835_PLLA_PER] = REGISTER_PLL_DIV( 16728c2ecf20Sopenharmony_ci SOC_ALL, 16738c2ecf20Sopenharmony_ci .name = "plla_per", 16748c2ecf20Sopenharmony_ci .source_pll = "plla", 16758c2ecf20Sopenharmony_ci .cm_reg = CM_PLLA, 16768c2ecf20Sopenharmony_ci .a2w_reg = A2W_PLLA_PER, 16778c2ecf20Sopenharmony_ci .load_mask = CM_PLLA_LOADPER, 16788c2ecf20Sopenharmony_ci .hold_mask = CM_PLLA_HOLDPER, 16798c2ecf20Sopenharmony_ci .fixed_divider = 1, 16808c2ecf20Sopenharmony_ci .flags = CLK_SET_RATE_PARENT), 16818c2ecf20Sopenharmony_ci [BCM2835_PLLA_DSI0] = REGISTER_PLL_DIV( 16828c2ecf20Sopenharmony_ci SOC_ALL, 16838c2ecf20Sopenharmony_ci .name = "plla_dsi0", 16848c2ecf20Sopenharmony_ci .source_pll = "plla", 16858c2ecf20Sopenharmony_ci .cm_reg = CM_PLLA, 16868c2ecf20Sopenharmony_ci .a2w_reg = A2W_PLLA_DSI0, 16878c2ecf20Sopenharmony_ci .load_mask = CM_PLLA_LOADDSI0, 16888c2ecf20Sopenharmony_ci .hold_mask = CM_PLLA_HOLDDSI0, 16898c2ecf20Sopenharmony_ci .fixed_divider = 1), 16908c2ecf20Sopenharmony_ci [BCM2835_PLLA_CCP2] = REGISTER_PLL_DIV( 16918c2ecf20Sopenharmony_ci SOC_ALL, 16928c2ecf20Sopenharmony_ci .name = "plla_ccp2", 16938c2ecf20Sopenharmony_ci .source_pll = "plla", 16948c2ecf20Sopenharmony_ci .cm_reg = CM_PLLA, 16958c2ecf20Sopenharmony_ci .a2w_reg = A2W_PLLA_CCP2, 16968c2ecf20Sopenharmony_ci .load_mask = CM_PLLA_LOADCCP2, 16978c2ecf20Sopenharmony_ci .hold_mask = CM_PLLA_HOLDCCP2, 16988c2ecf20Sopenharmony_ci .fixed_divider = 1, 16998c2ecf20Sopenharmony_ci .flags = CLK_SET_RATE_PARENT), 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci /* PLLB is used for the ARM's clock. */ 17028c2ecf20Sopenharmony_ci [BCM2835_PLLB] = REGISTER_PLL( 17038c2ecf20Sopenharmony_ci SOC_ALL, 17048c2ecf20Sopenharmony_ci .name = "pllb", 17058c2ecf20Sopenharmony_ci .cm_ctrl_reg = CM_PLLB, 17068c2ecf20Sopenharmony_ci .a2w_ctrl_reg = A2W_PLLB_CTRL, 17078c2ecf20Sopenharmony_ci .frac_reg = A2W_PLLB_FRAC, 17088c2ecf20Sopenharmony_ci .ana_reg_base = A2W_PLLB_ANA0, 17098c2ecf20Sopenharmony_ci .reference_enable_mask = A2W_XOSC_CTRL_PLLB_ENABLE, 17108c2ecf20Sopenharmony_ci .lock_mask = CM_LOCK_FLOCKB, 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci .ana = &bcm2835_ana_default, 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_ci .min_rate = 600000000u, 17158c2ecf20Sopenharmony_ci .max_rate = 3000000000u, 17168c2ecf20Sopenharmony_ci .max_fb_rate = BCM2835_MAX_FB_RATE, 17178c2ecf20Sopenharmony_ci .flags = CLK_GET_RATE_NOCACHE), 17188c2ecf20Sopenharmony_ci [BCM2835_PLLB_ARM] = REGISTER_PLL_DIV( 17198c2ecf20Sopenharmony_ci SOC_ALL, 17208c2ecf20Sopenharmony_ci .name = "pllb_arm", 17218c2ecf20Sopenharmony_ci .source_pll = "pllb", 17228c2ecf20Sopenharmony_ci .cm_reg = CM_PLLB, 17238c2ecf20Sopenharmony_ci .a2w_reg = A2W_PLLB_ARM, 17248c2ecf20Sopenharmony_ci .load_mask = CM_PLLB_LOADARM, 17258c2ecf20Sopenharmony_ci .hold_mask = CM_PLLB_HOLDARM, 17268c2ecf20Sopenharmony_ci .fixed_divider = 1, 17278c2ecf20Sopenharmony_ci .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE), 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci /* 17308c2ecf20Sopenharmony_ci * PLLC is the core PLL, used to drive the core VPU clock. 17318c2ecf20Sopenharmony_ci * 17328c2ecf20Sopenharmony_ci * It is in the PX LDO power domain, which is on when the 17338c2ecf20Sopenharmony_ci * AUDIO domain is on. 17348c2ecf20Sopenharmony_ci */ 17358c2ecf20Sopenharmony_ci [BCM2835_PLLC] = REGISTER_PLL( 17368c2ecf20Sopenharmony_ci SOC_ALL, 17378c2ecf20Sopenharmony_ci .name = "pllc", 17388c2ecf20Sopenharmony_ci .cm_ctrl_reg = CM_PLLC, 17398c2ecf20Sopenharmony_ci .a2w_ctrl_reg = A2W_PLLC_CTRL, 17408c2ecf20Sopenharmony_ci .frac_reg = A2W_PLLC_FRAC, 17418c2ecf20Sopenharmony_ci .ana_reg_base = A2W_PLLC_ANA0, 17428c2ecf20Sopenharmony_ci .reference_enable_mask = A2W_XOSC_CTRL_PLLC_ENABLE, 17438c2ecf20Sopenharmony_ci .lock_mask = CM_LOCK_FLOCKC, 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci .ana = &bcm2835_ana_default, 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci .min_rate = 600000000u, 17488c2ecf20Sopenharmony_ci .max_rate = 3000000000u, 17498c2ecf20Sopenharmony_ci .max_fb_rate = BCM2835_MAX_FB_RATE), 17508c2ecf20Sopenharmony_ci [BCM2835_PLLC_CORE0] = REGISTER_PLL_DIV( 17518c2ecf20Sopenharmony_ci SOC_ALL, 17528c2ecf20Sopenharmony_ci .name = "pllc_core0", 17538c2ecf20Sopenharmony_ci .source_pll = "pllc", 17548c2ecf20Sopenharmony_ci .cm_reg = CM_PLLC, 17558c2ecf20Sopenharmony_ci .a2w_reg = A2W_PLLC_CORE0, 17568c2ecf20Sopenharmony_ci .load_mask = CM_PLLC_LOADCORE0, 17578c2ecf20Sopenharmony_ci .hold_mask = CM_PLLC_HOLDCORE0, 17588c2ecf20Sopenharmony_ci .fixed_divider = 1, 17598c2ecf20Sopenharmony_ci .flags = CLK_SET_RATE_PARENT), 17608c2ecf20Sopenharmony_ci [BCM2835_PLLC_CORE1] = REGISTER_PLL_DIV( 17618c2ecf20Sopenharmony_ci SOC_ALL, 17628c2ecf20Sopenharmony_ci .name = "pllc_core1", 17638c2ecf20Sopenharmony_ci .source_pll = "pllc", 17648c2ecf20Sopenharmony_ci .cm_reg = CM_PLLC, 17658c2ecf20Sopenharmony_ci .a2w_reg = A2W_PLLC_CORE1, 17668c2ecf20Sopenharmony_ci .load_mask = CM_PLLC_LOADCORE1, 17678c2ecf20Sopenharmony_ci .hold_mask = CM_PLLC_HOLDCORE1, 17688c2ecf20Sopenharmony_ci .fixed_divider = 1, 17698c2ecf20Sopenharmony_ci .flags = CLK_SET_RATE_PARENT), 17708c2ecf20Sopenharmony_ci [BCM2835_PLLC_CORE2] = REGISTER_PLL_DIV( 17718c2ecf20Sopenharmony_ci SOC_ALL, 17728c2ecf20Sopenharmony_ci .name = "pllc_core2", 17738c2ecf20Sopenharmony_ci .source_pll = "pllc", 17748c2ecf20Sopenharmony_ci .cm_reg = CM_PLLC, 17758c2ecf20Sopenharmony_ci .a2w_reg = A2W_PLLC_CORE2, 17768c2ecf20Sopenharmony_ci .load_mask = CM_PLLC_LOADCORE2, 17778c2ecf20Sopenharmony_ci .hold_mask = CM_PLLC_HOLDCORE2, 17788c2ecf20Sopenharmony_ci .fixed_divider = 1, 17798c2ecf20Sopenharmony_ci .flags = CLK_SET_RATE_PARENT), 17808c2ecf20Sopenharmony_ci [BCM2835_PLLC_PER] = REGISTER_PLL_DIV( 17818c2ecf20Sopenharmony_ci SOC_ALL, 17828c2ecf20Sopenharmony_ci .name = "pllc_per", 17838c2ecf20Sopenharmony_ci .source_pll = "pllc", 17848c2ecf20Sopenharmony_ci .cm_reg = CM_PLLC, 17858c2ecf20Sopenharmony_ci .a2w_reg = A2W_PLLC_PER, 17868c2ecf20Sopenharmony_ci .load_mask = CM_PLLC_LOADPER, 17878c2ecf20Sopenharmony_ci .hold_mask = CM_PLLC_HOLDPER, 17888c2ecf20Sopenharmony_ci .fixed_divider = 1, 17898c2ecf20Sopenharmony_ci .flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT), 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci /* 17928c2ecf20Sopenharmony_ci * PLLD is the display PLL, used to drive DSI display panels. 17938c2ecf20Sopenharmony_ci * 17948c2ecf20Sopenharmony_ci * It is in the PX LDO power domain, which is on when the 17958c2ecf20Sopenharmony_ci * AUDIO domain is on. 17968c2ecf20Sopenharmony_ci */ 17978c2ecf20Sopenharmony_ci [BCM2835_PLLD] = REGISTER_PLL( 17988c2ecf20Sopenharmony_ci SOC_ALL, 17998c2ecf20Sopenharmony_ci .name = "plld", 18008c2ecf20Sopenharmony_ci .cm_ctrl_reg = CM_PLLD, 18018c2ecf20Sopenharmony_ci .a2w_ctrl_reg = A2W_PLLD_CTRL, 18028c2ecf20Sopenharmony_ci .frac_reg = A2W_PLLD_FRAC, 18038c2ecf20Sopenharmony_ci .ana_reg_base = A2W_PLLD_ANA0, 18048c2ecf20Sopenharmony_ci .reference_enable_mask = A2W_XOSC_CTRL_DDR_ENABLE, 18058c2ecf20Sopenharmony_ci .lock_mask = CM_LOCK_FLOCKD, 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci .ana = &bcm2835_ana_default, 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci .min_rate = 600000000u, 18108c2ecf20Sopenharmony_ci .max_rate = 2400000000u, 18118c2ecf20Sopenharmony_ci .max_fb_rate = BCM2835_MAX_FB_RATE), 18128c2ecf20Sopenharmony_ci [BCM2835_PLLD_CORE] = REGISTER_PLL_DIV( 18138c2ecf20Sopenharmony_ci SOC_ALL, 18148c2ecf20Sopenharmony_ci .name = "plld_core", 18158c2ecf20Sopenharmony_ci .source_pll = "plld", 18168c2ecf20Sopenharmony_ci .cm_reg = CM_PLLD, 18178c2ecf20Sopenharmony_ci .a2w_reg = A2W_PLLD_CORE, 18188c2ecf20Sopenharmony_ci .load_mask = CM_PLLD_LOADCORE, 18198c2ecf20Sopenharmony_ci .hold_mask = CM_PLLD_HOLDCORE, 18208c2ecf20Sopenharmony_ci .fixed_divider = 1, 18218c2ecf20Sopenharmony_ci .flags = CLK_SET_RATE_PARENT), 18228c2ecf20Sopenharmony_ci /* 18238c2ecf20Sopenharmony_ci * VPU firmware assumes that PLLD_PER isn't disabled by the ARM core. 18248c2ecf20Sopenharmony_ci * Otherwise this could cause firmware lookups. That's why we mark 18258c2ecf20Sopenharmony_ci * it as critical. 18268c2ecf20Sopenharmony_ci */ 18278c2ecf20Sopenharmony_ci [BCM2835_PLLD_PER] = REGISTER_PLL_DIV( 18288c2ecf20Sopenharmony_ci SOC_ALL, 18298c2ecf20Sopenharmony_ci .name = "plld_per", 18308c2ecf20Sopenharmony_ci .source_pll = "plld", 18318c2ecf20Sopenharmony_ci .cm_reg = CM_PLLD, 18328c2ecf20Sopenharmony_ci .a2w_reg = A2W_PLLD_PER, 18338c2ecf20Sopenharmony_ci .load_mask = CM_PLLD_LOADPER, 18348c2ecf20Sopenharmony_ci .hold_mask = CM_PLLD_HOLDPER, 18358c2ecf20Sopenharmony_ci .fixed_divider = 1, 18368c2ecf20Sopenharmony_ci .flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT), 18378c2ecf20Sopenharmony_ci [BCM2835_PLLD_DSI0] = REGISTER_PLL_DIV( 18388c2ecf20Sopenharmony_ci SOC_ALL, 18398c2ecf20Sopenharmony_ci .name = "plld_dsi0", 18408c2ecf20Sopenharmony_ci .source_pll = "plld", 18418c2ecf20Sopenharmony_ci .cm_reg = CM_PLLD, 18428c2ecf20Sopenharmony_ci .a2w_reg = A2W_PLLD_DSI0, 18438c2ecf20Sopenharmony_ci .load_mask = CM_PLLD_LOADDSI0, 18448c2ecf20Sopenharmony_ci .hold_mask = CM_PLLD_HOLDDSI0, 18458c2ecf20Sopenharmony_ci .fixed_divider = 1), 18468c2ecf20Sopenharmony_ci [BCM2835_PLLD_DSI1] = REGISTER_PLL_DIV( 18478c2ecf20Sopenharmony_ci SOC_ALL, 18488c2ecf20Sopenharmony_ci .name = "plld_dsi1", 18498c2ecf20Sopenharmony_ci .source_pll = "plld", 18508c2ecf20Sopenharmony_ci .cm_reg = CM_PLLD, 18518c2ecf20Sopenharmony_ci .a2w_reg = A2W_PLLD_DSI1, 18528c2ecf20Sopenharmony_ci .load_mask = CM_PLLD_LOADDSI1, 18538c2ecf20Sopenharmony_ci .hold_mask = CM_PLLD_HOLDDSI1, 18548c2ecf20Sopenharmony_ci .fixed_divider = 1), 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci /* 18578c2ecf20Sopenharmony_ci * PLLH is used to supply the pixel clock or the AUX clock for the 18588c2ecf20Sopenharmony_ci * TV encoder. 18598c2ecf20Sopenharmony_ci * 18608c2ecf20Sopenharmony_ci * It is in the HDMI power domain. 18618c2ecf20Sopenharmony_ci */ 18628c2ecf20Sopenharmony_ci [BCM2835_PLLH] = REGISTER_PLL( 18638c2ecf20Sopenharmony_ci SOC_BCM2835, 18648c2ecf20Sopenharmony_ci "pllh", 18658c2ecf20Sopenharmony_ci .cm_ctrl_reg = CM_PLLH, 18668c2ecf20Sopenharmony_ci .a2w_ctrl_reg = A2W_PLLH_CTRL, 18678c2ecf20Sopenharmony_ci .frac_reg = A2W_PLLH_FRAC, 18688c2ecf20Sopenharmony_ci .ana_reg_base = A2W_PLLH_ANA0, 18698c2ecf20Sopenharmony_ci .reference_enable_mask = A2W_XOSC_CTRL_PLLC_ENABLE, 18708c2ecf20Sopenharmony_ci .lock_mask = CM_LOCK_FLOCKH, 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci .ana = &bcm2835_ana_pllh, 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci .min_rate = 600000000u, 18758c2ecf20Sopenharmony_ci .max_rate = 3000000000u, 18768c2ecf20Sopenharmony_ci .max_fb_rate = BCM2835_MAX_FB_RATE), 18778c2ecf20Sopenharmony_ci [BCM2835_PLLH_RCAL] = REGISTER_PLL_DIV( 18788c2ecf20Sopenharmony_ci SOC_BCM2835, 18798c2ecf20Sopenharmony_ci .name = "pllh_rcal", 18808c2ecf20Sopenharmony_ci .source_pll = "pllh", 18818c2ecf20Sopenharmony_ci .cm_reg = CM_PLLH, 18828c2ecf20Sopenharmony_ci .a2w_reg = A2W_PLLH_RCAL, 18838c2ecf20Sopenharmony_ci .load_mask = CM_PLLH_LOADRCAL, 18848c2ecf20Sopenharmony_ci .hold_mask = 0, 18858c2ecf20Sopenharmony_ci .fixed_divider = 10, 18868c2ecf20Sopenharmony_ci .flags = CLK_SET_RATE_PARENT), 18878c2ecf20Sopenharmony_ci [BCM2835_PLLH_AUX] = REGISTER_PLL_DIV( 18888c2ecf20Sopenharmony_ci SOC_BCM2835, 18898c2ecf20Sopenharmony_ci .name = "pllh_aux", 18908c2ecf20Sopenharmony_ci .source_pll = "pllh", 18918c2ecf20Sopenharmony_ci .cm_reg = CM_PLLH, 18928c2ecf20Sopenharmony_ci .a2w_reg = A2W_PLLH_AUX, 18938c2ecf20Sopenharmony_ci .load_mask = CM_PLLH_LOADAUX, 18948c2ecf20Sopenharmony_ci .hold_mask = 0, 18958c2ecf20Sopenharmony_ci .fixed_divider = 1, 18968c2ecf20Sopenharmony_ci .flags = CLK_SET_RATE_PARENT), 18978c2ecf20Sopenharmony_ci [BCM2835_PLLH_PIX] = REGISTER_PLL_DIV( 18988c2ecf20Sopenharmony_ci SOC_BCM2835, 18998c2ecf20Sopenharmony_ci .name = "pllh_pix", 19008c2ecf20Sopenharmony_ci .source_pll = "pllh", 19018c2ecf20Sopenharmony_ci .cm_reg = CM_PLLH, 19028c2ecf20Sopenharmony_ci .a2w_reg = A2W_PLLH_PIX, 19038c2ecf20Sopenharmony_ci .load_mask = CM_PLLH_LOADPIX, 19048c2ecf20Sopenharmony_ci .hold_mask = 0, 19058c2ecf20Sopenharmony_ci .fixed_divider = 10, 19068c2ecf20Sopenharmony_ci .flags = CLK_SET_RATE_PARENT), 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci /* the clocks */ 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci /* clocks with oscillator parent mux */ 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci /* One Time Programmable Memory clock. Maximum 10Mhz. */ 19138c2ecf20Sopenharmony_ci [BCM2835_CLOCK_OTP] = REGISTER_OSC_CLK( 19148c2ecf20Sopenharmony_ci SOC_ALL, 19158c2ecf20Sopenharmony_ci .name = "otp", 19168c2ecf20Sopenharmony_ci .ctl_reg = CM_OTPCTL, 19178c2ecf20Sopenharmony_ci .div_reg = CM_OTPDIV, 19188c2ecf20Sopenharmony_ci .int_bits = 4, 19198c2ecf20Sopenharmony_ci .frac_bits = 0, 19208c2ecf20Sopenharmony_ci .tcnt_mux = 6), 19218c2ecf20Sopenharmony_ci /* 19228c2ecf20Sopenharmony_ci * Used for a 1Mhz clock for the system clocksource, and also used 19238c2ecf20Sopenharmony_ci * bythe watchdog timer and the camera pulse generator. 19248c2ecf20Sopenharmony_ci */ 19258c2ecf20Sopenharmony_ci [BCM2835_CLOCK_TIMER] = REGISTER_OSC_CLK( 19268c2ecf20Sopenharmony_ci SOC_ALL, 19278c2ecf20Sopenharmony_ci .name = "timer", 19288c2ecf20Sopenharmony_ci .ctl_reg = CM_TIMERCTL, 19298c2ecf20Sopenharmony_ci .div_reg = CM_TIMERDIV, 19308c2ecf20Sopenharmony_ci .int_bits = 6, 19318c2ecf20Sopenharmony_ci .frac_bits = 12), 19328c2ecf20Sopenharmony_ci /* 19338c2ecf20Sopenharmony_ci * Clock for the temperature sensor. 19348c2ecf20Sopenharmony_ci * Generally run at 2Mhz, max 5Mhz. 19358c2ecf20Sopenharmony_ci */ 19368c2ecf20Sopenharmony_ci [BCM2835_CLOCK_TSENS] = REGISTER_OSC_CLK( 19378c2ecf20Sopenharmony_ci SOC_ALL, 19388c2ecf20Sopenharmony_ci .name = "tsens", 19398c2ecf20Sopenharmony_ci .ctl_reg = CM_TSENSCTL, 19408c2ecf20Sopenharmony_ci .div_reg = CM_TSENSDIV, 19418c2ecf20Sopenharmony_ci .int_bits = 5, 19428c2ecf20Sopenharmony_ci .frac_bits = 0), 19438c2ecf20Sopenharmony_ci [BCM2835_CLOCK_TEC] = REGISTER_OSC_CLK( 19448c2ecf20Sopenharmony_ci SOC_ALL, 19458c2ecf20Sopenharmony_ci .name = "tec", 19468c2ecf20Sopenharmony_ci .ctl_reg = CM_TECCTL, 19478c2ecf20Sopenharmony_ci .div_reg = CM_TECDIV, 19488c2ecf20Sopenharmony_ci .int_bits = 6, 19498c2ecf20Sopenharmony_ci .frac_bits = 0), 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci /* clocks with vpu parent mux */ 19528c2ecf20Sopenharmony_ci [BCM2835_CLOCK_H264] = REGISTER_VPU_CLK( 19538c2ecf20Sopenharmony_ci SOC_ALL, 19548c2ecf20Sopenharmony_ci .name = "h264", 19558c2ecf20Sopenharmony_ci .ctl_reg = CM_H264CTL, 19568c2ecf20Sopenharmony_ci .div_reg = CM_H264DIV, 19578c2ecf20Sopenharmony_ci .int_bits = 4, 19588c2ecf20Sopenharmony_ci .frac_bits = 8, 19598c2ecf20Sopenharmony_ci .tcnt_mux = 1), 19608c2ecf20Sopenharmony_ci [BCM2835_CLOCK_ISP] = REGISTER_VPU_CLK( 19618c2ecf20Sopenharmony_ci SOC_ALL, 19628c2ecf20Sopenharmony_ci .name = "isp", 19638c2ecf20Sopenharmony_ci .ctl_reg = CM_ISPCTL, 19648c2ecf20Sopenharmony_ci .div_reg = CM_ISPDIV, 19658c2ecf20Sopenharmony_ci .int_bits = 4, 19668c2ecf20Sopenharmony_ci .frac_bits = 8, 19678c2ecf20Sopenharmony_ci .tcnt_mux = 2), 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci /* 19708c2ecf20Sopenharmony_ci * Secondary SDRAM clock. Used for low-voltage modes when the PLL 19718c2ecf20Sopenharmony_ci * in the SDRAM controller can't be used. 19728c2ecf20Sopenharmony_ci */ 19738c2ecf20Sopenharmony_ci [BCM2835_CLOCK_SDRAM] = REGISTER_VPU_CLK( 19748c2ecf20Sopenharmony_ci SOC_ALL, 19758c2ecf20Sopenharmony_ci .name = "sdram", 19768c2ecf20Sopenharmony_ci .ctl_reg = CM_SDCCTL, 19778c2ecf20Sopenharmony_ci .div_reg = CM_SDCDIV, 19788c2ecf20Sopenharmony_ci .int_bits = 6, 19798c2ecf20Sopenharmony_ci .frac_bits = 0, 19808c2ecf20Sopenharmony_ci .tcnt_mux = 3), 19818c2ecf20Sopenharmony_ci [BCM2835_CLOCK_V3D] = REGISTER_VPU_CLK( 19828c2ecf20Sopenharmony_ci SOC_ALL, 19838c2ecf20Sopenharmony_ci .name = "v3d", 19848c2ecf20Sopenharmony_ci .ctl_reg = CM_V3DCTL, 19858c2ecf20Sopenharmony_ci .div_reg = CM_V3DDIV, 19868c2ecf20Sopenharmony_ci .int_bits = 4, 19878c2ecf20Sopenharmony_ci .frac_bits = 8, 19888c2ecf20Sopenharmony_ci .tcnt_mux = 4), 19898c2ecf20Sopenharmony_ci /* 19908c2ecf20Sopenharmony_ci * VPU clock. This doesn't have an enable bit, since it drives 19918c2ecf20Sopenharmony_ci * the bus for everything else, and is special so it doesn't need 19928c2ecf20Sopenharmony_ci * to be gated for rate changes. It is also known as "clk_audio" 19938c2ecf20Sopenharmony_ci * in various hardware documentation. 19948c2ecf20Sopenharmony_ci */ 19958c2ecf20Sopenharmony_ci [BCM2835_CLOCK_VPU] = REGISTER_VPU_CLK( 19968c2ecf20Sopenharmony_ci SOC_ALL, 19978c2ecf20Sopenharmony_ci .name = "vpu", 19988c2ecf20Sopenharmony_ci .ctl_reg = CM_VPUCTL, 19998c2ecf20Sopenharmony_ci .div_reg = CM_VPUDIV, 20008c2ecf20Sopenharmony_ci .int_bits = 12, 20018c2ecf20Sopenharmony_ci .frac_bits = 8, 20028c2ecf20Sopenharmony_ci .flags = CLK_IS_CRITICAL, 20038c2ecf20Sopenharmony_ci .is_vpu_clock = true, 20048c2ecf20Sopenharmony_ci .tcnt_mux = 5), 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci /* clocks with per parent mux */ 20078c2ecf20Sopenharmony_ci [BCM2835_CLOCK_AVEO] = REGISTER_PER_CLK( 20088c2ecf20Sopenharmony_ci SOC_ALL, 20098c2ecf20Sopenharmony_ci .name = "aveo", 20108c2ecf20Sopenharmony_ci .ctl_reg = CM_AVEOCTL, 20118c2ecf20Sopenharmony_ci .div_reg = CM_AVEODIV, 20128c2ecf20Sopenharmony_ci .int_bits = 4, 20138c2ecf20Sopenharmony_ci .frac_bits = 0, 20148c2ecf20Sopenharmony_ci .tcnt_mux = 38), 20158c2ecf20Sopenharmony_ci [BCM2835_CLOCK_CAM0] = REGISTER_PER_CLK( 20168c2ecf20Sopenharmony_ci SOC_ALL, 20178c2ecf20Sopenharmony_ci .name = "cam0", 20188c2ecf20Sopenharmony_ci .ctl_reg = CM_CAM0CTL, 20198c2ecf20Sopenharmony_ci .div_reg = CM_CAM0DIV, 20208c2ecf20Sopenharmony_ci .int_bits = 4, 20218c2ecf20Sopenharmony_ci .frac_bits = 8, 20228c2ecf20Sopenharmony_ci .tcnt_mux = 14), 20238c2ecf20Sopenharmony_ci [BCM2835_CLOCK_CAM1] = REGISTER_PER_CLK( 20248c2ecf20Sopenharmony_ci SOC_ALL, 20258c2ecf20Sopenharmony_ci .name = "cam1", 20268c2ecf20Sopenharmony_ci .ctl_reg = CM_CAM1CTL, 20278c2ecf20Sopenharmony_ci .div_reg = CM_CAM1DIV, 20288c2ecf20Sopenharmony_ci .int_bits = 4, 20298c2ecf20Sopenharmony_ci .frac_bits = 8, 20308c2ecf20Sopenharmony_ci .tcnt_mux = 15), 20318c2ecf20Sopenharmony_ci [BCM2835_CLOCK_DFT] = REGISTER_PER_CLK( 20328c2ecf20Sopenharmony_ci SOC_ALL, 20338c2ecf20Sopenharmony_ci .name = "dft", 20348c2ecf20Sopenharmony_ci .ctl_reg = CM_DFTCTL, 20358c2ecf20Sopenharmony_ci .div_reg = CM_DFTDIV, 20368c2ecf20Sopenharmony_ci .int_bits = 5, 20378c2ecf20Sopenharmony_ci .frac_bits = 0), 20388c2ecf20Sopenharmony_ci [BCM2835_CLOCK_DPI] = REGISTER_PER_CLK( 20398c2ecf20Sopenharmony_ci SOC_ALL, 20408c2ecf20Sopenharmony_ci .name = "dpi", 20418c2ecf20Sopenharmony_ci .ctl_reg = CM_DPICTL, 20428c2ecf20Sopenharmony_ci .div_reg = CM_DPIDIV, 20438c2ecf20Sopenharmony_ci .int_bits = 4, 20448c2ecf20Sopenharmony_ci .frac_bits = 8, 20458c2ecf20Sopenharmony_ci .tcnt_mux = 17), 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci /* Arasan EMMC clock */ 20488c2ecf20Sopenharmony_ci [BCM2835_CLOCK_EMMC] = REGISTER_PER_CLK( 20498c2ecf20Sopenharmony_ci SOC_ALL, 20508c2ecf20Sopenharmony_ci .name = "emmc", 20518c2ecf20Sopenharmony_ci .ctl_reg = CM_EMMCCTL, 20528c2ecf20Sopenharmony_ci .div_reg = CM_EMMCDIV, 20538c2ecf20Sopenharmony_ci .int_bits = 4, 20548c2ecf20Sopenharmony_ci .frac_bits = 8, 20558c2ecf20Sopenharmony_ci .tcnt_mux = 39), 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci /* EMMC2 clock (only available for BCM2711) */ 20588c2ecf20Sopenharmony_ci [BCM2711_CLOCK_EMMC2] = REGISTER_PER_CLK( 20598c2ecf20Sopenharmony_ci SOC_BCM2711, 20608c2ecf20Sopenharmony_ci .name = "emmc2", 20618c2ecf20Sopenharmony_ci .ctl_reg = CM_EMMC2CTL, 20628c2ecf20Sopenharmony_ci .div_reg = CM_EMMC2DIV, 20638c2ecf20Sopenharmony_ci .int_bits = 4, 20648c2ecf20Sopenharmony_ci .frac_bits = 8, 20658c2ecf20Sopenharmony_ci .tcnt_mux = 42), 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci /* General purpose (GPIO) clocks */ 20688c2ecf20Sopenharmony_ci [BCM2835_CLOCK_GP0] = REGISTER_PER_CLK( 20698c2ecf20Sopenharmony_ci SOC_ALL, 20708c2ecf20Sopenharmony_ci .name = "gp0", 20718c2ecf20Sopenharmony_ci .ctl_reg = CM_GP0CTL, 20728c2ecf20Sopenharmony_ci .div_reg = CM_GP0DIV, 20738c2ecf20Sopenharmony_ci .int_bits = 12, 20748c2ecf20Sopenharmony_ci .frac_bits = 12, 20758c2ecf20Sopenharmony_ci .is_mash_clock = true, 20768c2ecf20Sopenharmony_ci .tcnt_mux = 20), 20778c2ecf20Sopenharmony_ci [BCM2835_CLOCK_GP1] = REGISTER_PER_CLK( 20788c2ecf20Sopenharmony_ci SOC_ALL, 20798c2ecf20Sopenharmony_ci .name = "gp1", 20808c2ecf20Sopenharmony_ci .ctl_reg = CM_GP1CTL, 20818c2ecf20Sopenharmony_ci .div_reg = CM_GP1DIV, 20828c2ecf20Sopenharmony_ci .int_bits = 12, 20838c2ecf20Sopenharmony_ci .frac_bits = 12, 20848c2ecf20Sopenharmony_ci .flags = CLK_IS_CRITICAL, 20858c2ecf20Sopenharmony_ci .is_mash_clock = true, 20868c2ecf20Sopenharmony_ci .tcnt_mux = 21), 20878c2ecf20Sopenharmony_ci [BCM2835_CLOCK_GP2] = REGISTER_PER_CLK( 20888c2ecf20Sopenharmony_ci SOC_ALL, 20898c2ecf20Sopenharmony_ci .name = "gp2", 20908c2ecf20Sopenharmony_ci .ctl_reg = CM_GP2CTL, 20918c2ecf20Sopenharmony_ci .div_reg = CM_GP2DIV, 20928c2ecf20Sopenharmony_ci .int_bits = 12, 20938c2ecf20Sopenharmony_ci .frac_bits = 12, 20948c2ecf20Sopenharmony_ci .flags = CLK_IS_CRITICAL), 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci /* HDMI state machine */ 20978c2ecf20Sopenharmony_ci [BCM2835_CLOCK_HSM] = REGISTER_PER_CLK( 20988c2ecf20Sopenharmony_ci SOC_ALL, 20998c2ecf20Sopenharmony_ci .name = "hsm", 21008c2ecf20Sopenharmony_ci .ctl_reg = CM_HSMCTL, 21018c2ecf20Sopenharmony_ci .div_reg = CM_HSMDIV, 21028c2ecf20Sopenharmony_ci .int_bits = 4, 21038c2ecf20Sopenharmony_ci .frac_bits = 8, 21048c2ecf20Sopenharmony_ci .tcnt_mux = 22), 21058c2ecf20Sopenharmony_ci [BCM2835_CLOCK_PCM] = REGISTER_PCM_CLK( 21068c2ecf20Sopenharmony_ci SOC_ALL, 21078c2ecf20Sopenharmony_ci .name = "pcm", 21088c2ecf20Sopenharmony_ci .ctl_reg = CM_PCMCTL, 21098c2ecf20Sopenharmony_ci .div_reg = CM_PCMDIV, 21108c2ecf20Sopenharmony_ci .int_bits = 12, 21118c2ecf20Sopenharmony_ci .frac_bits = 12, 21128c2ecf20Sopenharmony_ci .is_mash_clock = true, 21138c2ecf20Sopenharmony_ci .low_jitter = true, 21148c2ecf20Sopenharmony_ci .tcnt_mux = 23), 21158c2ecf20Sopenharmony_ci [BCM2835_CLOCK_PWM] = REGISTER_PER_CLK( 21168c2ecf20Sopenharmony_ci SOC_ALL, 21178c2ecf20Sopenharmony_ci .name = "pwm", 21188c2ecf20Sopenharmony_ci .ctl_reg = CM_PWMCTL, 21198c2ecf20Sopenharmony_ci .div_reg = CM_PWMDIV, 21208c2ecf20Sopenharmony_ci .int_bits = 12, 21218c2ecf20Sopenharmony_ci .frac_bits = 12, 21228c2ecf20Sopenharmony_ci .is_mash_clock = true, 21238c2ecf20Sopenharmony_ci .tcnt_mux = 24), 21248c2ecf20Sopenharmony_ci [BCM2835_CLOCK_SLIM] = REGISTER_PER_CLK( 21258c2ecf20Sopenharmony_ci SOC_ALL, 21268c2ecf20Sopenharmony_ci .name = "slim", 21278c2ecf20Sopenharmony_ci .ctl_reg = CM_SLIMCTL, 21288c2ecf20Sopenharmony_ci .div_reg = CM_SLIMDIV, 21298c2ecf20Sopenharmony_ci .int_bits = 12, 21308c2ecf20Sopenharmony_ci .frac_bits = 12, 21318c2ecf20Sopenharmony_ci .is_mash_clock = true, 21328c2ecf20Sopenharmony_ci .tcnt_mux = 25), 21338c2ecf20Sopenharmony_ci [BCM2835_CLOCK_SMI] = REGISTER_PER_CLK( 21348c2ecf20Sopenharmony_ci SOC_ALL, 21358c2ecf20Sopenharmony_ci .name = "smi", 21368c2ecf20Sopenharmony_ci .ctl_reg = CM_SMICTL, 21378c2ecf20Sopenharmony_ci .div_reg = CM_SMIDIV, 21388c2ecf20Sopenharmony_ci .int_bits = 4, 21398c2ecf20Sopenharmony_ci .frac_bits = 8, 21408c2ecf20Sopenharmony_ci .tcnt_mux = 27), 21418c2ecf20Sopenharmony_ci [BCM2835_CLOCK_UART] = REGISTER_PER_CLK( 21428c2ecf20Sopenharmony_ci SOC_ALL, 21438c2ecf20Sopenharmony_ci .name = "uart", 21448c2ecf20Sopenharmony_ci .ctl_reg = CM_UARTCTL, 21458c2ecf20Sopenharmony_ci .div_reg = CM_UARTDIV, 21468c2ecf20Sopenharmony_ci .int_bits = 10, 21478c2ecf20Sopenharmony_ci .frac_bits = 12, 21488c2ecf20Sopenharmony_ci .tcnt_mux = 28), 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci /* TV encoder clock. Only operating frequency is 108Mhz. */ 21518c2ecf20Sopenharmony_ci [BCM2835_CLOCK_VEC] = REGISTER_PER_CLK( 21528c2ecf20Sopenharmony_ci SOC_ALL, 21538c2ecf20Sopenharmony_ci .name = "vec", 21548c2ecf20Sopenharmony_ci .ctl_reg = CM_VECCTL, 21558c2ecf20Sopenharmony_ci .div_reg = CM_VECDIV, 21568c2ecf20Sopenharmony_ci .int_bits = 4, 21578c2ecf20Sopenharmony_ci .frac_bits = 0, 21588c2ecf20Sopenharmony_ci /* 21598c2ecf20Sopenharmony_ci * Allow rate change propagation only on PLLH_AUX which is 21608c2ecf20Sopenharmony_ci * assigned index 7 in the parent array. 21618c2ecf20Sopenharmony_ci */ 21628c2ecf20Sopenharmony_ci .set_rate_parent = BIT(7), 21638c2ecf20Sopenharmony_ci .tcnt_mux = 29), 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci /* dsi clocks */ 21668c2ecf20Sopenharmony_ci [BCM2835_CLOCK_DSI0E] = REGISTER_PER_CLK( 21678c2ecf20Sopenharmony_ci SOC_ALL, 21688c2ecf20Sopenharmony_ci .name = "dsi0e", 21698c2ecf20Sopenharmony_ci .ctl_reg = CM_DSI0ECTL, 21708c2ecf20Sopenharmony_ci .div_reg = CM_DSI0EDIV, 21718c2ecf20Sopenharmony_ci .int_bits = 4, 21728c2ecf20Sopenharmony_ci .frac_bits = 8, 21738c2ecf20Sopenharmony_ci .tcnt_mux = 18), 21748c2ecf20Sopenharmony_ci [BCM2835_CLOCK_DSI1E] = REGISTER_PER_CLK( 21758c2ecf20Sopenharmony_ci SOC_ALL, 21768c2ecf20Sopenharmony_ci .name = "dsi1e", 21778c2ecf20Sopenharmony_ci .ctl_reg = CM_DSI1ECTL, 21788c2ecf20Sopenharmony_ci .div_reg = CM_DSI1EDIV, 21798c2ecf20Sopenharmony_ci .int_bits = 4, 21808c2ecf20Sopenharmony_ci .frac_bits = 8, 21818c2ecf20Sopenharmony_ci .tcnt_mux = 19), 21828c2ecf20Sopenharmony_ci [BCM2835_CLOCK_DSI0P] = REGISTER_DSI0_CLK( 21838c2ecf20Sopenharmony_ci SOC_ALL, 21848c2ecf20Sopenharmony_ci .name = "dsi0p", 21858c2ecf20Sopenharmony_ci .ctl_reg = CM_DSI0PCTL, 21868c2ecf20Sopenharmony_ci .div_reg = CM_DSI0PDIV, 21878c2ecf20Sopenharmony_ci .int_bits = 0, 21888c2ecf20Sopenharmony_ci .frac_bits = 0, 21898c2ecf20Sopenharmony_ci .tcnt_mux = 12), 21908c2ecf20Sopenharmony_ci [BCM2835_CLOCK_DSI1P] = REGISTER_DSI1_CLK( 21918c2ecf20Sopenharmony_ci SOC_ALL, 21928c2ecf20Sopenharmony_ci .name = "dsi1p", 21938c2ecf20Sopenharmony_ci .ctl_reg = CM_DSI1PCTL, 21948c2ecf20Sopenharmony_ci .div_reg = CM_DSI1PDIV, 21958c2ecf20Sopenharmony_ci .int_bits = 0, 21968c2ecf20Sopenharmony_ci .frac_bits = 0, 21978c2ecf20Sopenharmony_ci .tcnt_mux = 13), 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_ci /* the gates */ 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci /* 22028c2ecf20Sopenharmony_ci * CM_PERIICTL (and CM_PERIACTL, CM_SYSCTL and CM_VPUCTL if 22038c2ecf20Sopenharmony_ci * you have the debug bit set in the power manager, which we 22048c2ecf20Sopenharmony_ci * don't bother exposing) are individual gates off of the 22058c2ecf20Sopenharmony_ci * non-stop vpu clock. 22068c2ecf20Sopenharmony_ci */ 22078c2ecf20Sopenharmony_ci [BCM2835_CLOCK_PERI_IMAGE] = REGISTER_GATE( 22088c2ecf20Sopenharmony_ci SOC_ALL, 22098c2ecf20Sopenharmony_ci .name = "peri_image", 22108c2ecf20Sopenharmony_ci .parent = "vpu", 22118c2ecf20Sopenharmony_ci .ctl_reg = CM_PERIICTL), 22128c2ecf20Sopenharmony_ci}; 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci/* 22158c2ecf20Sopenharmony_ci * Permanently take a reference on the parent of the SDRAM clock. 22168c2ecf20Sopenharmony_ci * 22178c2ecf20Sopenharmony_ci * While the SDRAM is being driven by its dedicated PLL most of the 22188c2ecf20Sopenharmony_ci * time, there is a little loop running in the firmware that 22198c2ecf20Sopenharmony_ci * periodically switches the SDRAM to using our CM clock to do PVT 22208c2ecf20Sopenharmony_ci * recalibration, with the assumption that the previously configured 22218c2ecf20Sopenharmony_ci * SDRAM parent is still enabled and running. 22228c2ecf20Sopenharmony_ci */ 22238c2ecf20Sopenharmony_cistatic int bcm2835_mark_sdc_parent_critical(struct clk *sdc) 22248c2ecf20Sopenharmony_ci{ 22258c2ecf20Sopenharmony_ci struct clk *parent = clk_get_parent(sdc); 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci if (IS_ERR(parent)) 22288c2ecf20Sopenharmony_ci return PTR_ERR(parent); 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci return clk_prepare_enable(parent); 22318c2ecf20Sopenharmony_ci} 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_cistatic int bcm2835_clk_probe(struct platform_device *pdev) 22348c2ecf20Sopenharmony_ci{ 22358c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 22368c2ecf20Sopenharmony_ci struct clk_hw **hws; 22378c2ecf20Sopenharmony_ci struct bcm2835_cprman *cprman; 22388c2ecf20Sopenharmony_ci const struct bcm2835_clk_desc *desc; 22398c2ecf20Sopenharmony_ci const size_t asize = ARRAY_SIZE(clk_desc_array); 22408c2ecf20Sopenharmony_ci const struct cprman_plat_data *pdata; 22418c2ecf20Sopenharmony_ci size_t i; 22428c2ecf20Sopenharmony_ci int ret; 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci pdata = of_device_get_match_data(&pdev->dev); 22458c2ecf20Sopenharmony_ci if (!pdata) 22468c2ecf20Sopenharmony_ci return -ENODEV; 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci cprman = devm_kzalloc(dev, 22498c2ecf20Sopenharmony_ci struct_size(cprman, onecell.hws, asize), 22508c2ecf20Sopenharmony_ci GFP_KERNEL); 22518c2ecf20Sopenharmony_ci if (!cprman) 22528c2ecf20Sopenharmony_ci return -ENOMEM; 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci spin_lock_init(&cprman->regs_lock); 22558c2ecf20Sopenharmony_ci cprman->dev = dev; 22568c2ecf20Sopenharmony_ci cprman->regs = devm_platform_ioremap_resource(pdev, 0); 22578c2ecf20Sopenharmony_ci if (IS_ERR(cprman->regs)) 22588c2ecf20Sopenharmony_ci return PTR_ERR(cprman->regs); 22598c2ecf20Sopenharmony_ci 22608c2ecf20Sopenharmony_ci memcpy(cprman->real_parent_names, cprman_parent_names, 22618c2ecf20Sopenharmony_ci sizeof(cprman_parent_names)); 22628c2ecf20Sopenharmony_ci of_clk_parent_fill(dev->of_node, cprman->real_parent_names, 22638c2ecf20Sopenharmony_ci ARRAY_SIZE(cprman_parent_names)); 22648c2ecf20Sopenharmony_ci 22658c2ecf20Sopenharmony_ci /* 22668c2ecf20Sopenharmony_ci * Make sure the external oscillator has been registered. 22678c2ecf20Sopenharmony_ci * 22688c2ecf20Sopenharmony_ci * The other (DSI) clocks are not present on older device 22698c2ecf20Sopenharmony_ci * trees, which we still need to support for backwards 22708c2ecf20Sopenharmony_ci * compatibility. 22718c2ecf20Sopenharmony_ci */ 22728c2ecf20Sopenharmony_ci if (!cprman->real_parent_names[0]) 22738c2ecf20Sopenharmony_ci return -ENODEV; 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, cprman); 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_ci cprman->onecell.num = asize; 22788c2ecf20Sopenharmony_ci cprman->soc = pdata->soc; 22798c2ecf20Sopenharmony_ci hws = cprman->onecell.hws; 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci for (i = 0; i < asize; i++) { 22828c2ecf20Sopenharmony_ci desc = &clk_desc_array[i]; 22838c2ecf20Sopenharmony_ci if (desc->clk_register && desc->data && 22848c2ecf20Sopenharmony_ci (desc->supported & pdata->soc)) { 22858c2ecf20Sopenharmony_ci hws[i] = desc->clk_register(cprman, desc->data); 22868c2ecf20Sopenharmony_ci } 22878c2ecf20Sopenharmony_ci } 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci ret = bcm2835_mark_sdc_parent_critical(hws[BCM2835_CLOCK_SDRAM]->clk); 22908c2ecf20Sopenharmony_ci if (ret) 22918c2ecf20Sopenharmony_ci return ret; 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_ci return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, 22948c2ecf20Sopenharmony_ci &cprman->onecell); 22958c2ecf20Sopenharmony_ci} 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_cistatic const struct cprman_plat_data cprman_bcm2835_plat_data = { 22988c2ecf20Sopenharmony_ci .soc = SOC_BCM2835, 22998c2ecf20Sopenharmony_ci}; 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_cistatic const struct cprman_plat_data cprman_bcm2711_plat_data = { 23028c2ecf20Sopenharmony_ci .soc = SOC_BCM2711, 23038c2ecf20Sopenharmony_ci}; 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_cistatic const struct of_device_id bcm2835_clk_of_match[] = { 23068c2ecf20Sopenharmony_ci { .compatible = "brcm,bcm2835-cprman", .data = &cprman_bcm2835_plat_data }, 23078c2ecf20Sopenharmony_ci { .compatible = "brcm,bcm2711-cprman", .data = &cprman_bcm2711_plat_data }, 23088c2ecf20Sopenharmony_ci {} 23098c2ecf20Sopenharmony_ci}; 23108c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, bcm2835_clk_of_match); 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_cistatic struct platform_driver bcm2835_clk_driver = { 23138c2ecf20Sopenharmony_ci .driver = { 23148c2ecf20Sopenharmony_ci .name = "bcm2835-clk", 23158c2ecf20Sopenharmony_ci .of_match_table = bcm2835_clk_of_match, 23168c2ecf20Sopenharmony_ci }, 23178c2ecf20Sopenharmony_ci .probe = bcm2835_clk_probe, 23188c2ecf20Sopenharmony_ci}; 23198c2ecf20Sopenharmony_ci 23208c2ecf20Sopenharmony_cibuiltin_platform_driver(bcm2835_clk_driver); 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ciMODULE_AUTHOR("Eric Anholt <eric@anholt.net>"); 23238c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("BCM2835 clock driver"); 23248c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2325