1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2ff1930c6SPaul Burton /* 3ff1930c6SPaul Burton * Ingenic JZ4740 SoC CGU driver 4ff1930c6SPaul Burton * 5ff1930c6SPaul Burton * Copyright (c) 2015 Imagination Technologies 6fb615d61SPaul Burton * Author: Paul Burton <paul.burton@mips.com> 7ff1930c6SPaul Burton */ 8ff1930c6SPaul Burton 9ff1930c6SPaul Burton #include <linux/clk-provider.h> 10ff1930c6SPaul Burton #include <linux/delay.h> 1162e59c4eSStephen Boyd #include <linux/io.h> 12ff1930c6SPaul Burton #include <linux/of.h> 139d9cc58aS周琰杰 (Zhou Yanjie) 14c4a11bf4SPaul Cercueil #include <dt-bindings/clock/ingenic,jz4740-cgu.h> 159d9cc58aS周琰杰 (Zhou Yanjie) 16ff1930c6SPaul Burton #include "cgu.h" 172ee93e3cSPaul Cercueil #include "pm.h" 18ff1930c6SPaul Burton 19ff1930c6SPaul Burton /* CGU register offsets */ 20ff1930c6SPaul Burton #define CGU_REG_CPCCR 0x00 2141dd641eSPaul Burton #define CGU_REG_LCR 0x04 22ff1930c6SPaul Burton #define CGU_REG_CPPCR 0x10 23ed286ca5SPaul Burton #define CGU_REG_CLKGR 0x20 24ff1930c6SPaul Burton #define CGU_REG_SCR 0x24 25ff1930c6SPaul Burton #define CGU_REG_I2SCDR 0x60 26ff1930c6SPaul Burton #define CGU_REG_LPCDR 0x64 27ff1930c6SPaul Burton #define CGU_REG_MSCCDR 0x68 28ff1930c6SPaul Burton #define CGU_REG_UHCCDR 0x6c 29ff1930c6SPaul Burton #define CGU_REG_SSICDR 0x74 30ff1930c6SPaul Burton 31ff1930c6SPaul Burton /* bits within a PLL control register */ 32ff1930c6SPaul Burton #define PLLCTL_M_SHIFT 23 33ff1930c6SPaul Burton #define PLLCTL_M_MASK (0x1ff << PLLCTL_M_SHIFT) 34ff1930c6SPaul Burton #define PLLCTL_N_SHIFT 18 35ff1930c6SPaul Burton #define PLLCTL_N_MASK (0x1f << PLLCTL_N_SHIFT) 36ff1930c6SPaul Burton #define PLLCTL_OD_SHIFT 16 37ff1930c6SPaul Burton #define PLLCTL_OD_MASK (0x3 << PLLCTL_OD_SHIFT) 38ff1930c6SPaul Burton #define PLLCTL_STABLE (1 << 10) 39ff1930c6SPaul Burton #define PLLCTL_BYPASS (1 << 9) 40ff1930c6SPaul Burton #define PLLCTL_ENABLE (1 << 8) 41ff1930c6SPaul Burton 4241dd641eSPaul Burton /* bits within the LCR register */ 4341dd641eSPaul Burton #define LCR_SLEEP (1 << 0) 4441dd641eSPaul Burton 45ed286ca5SPaul Burton /* bits within the CLKGR register */ 46ed286ca5SPaul Burton #define CLKGR_UDC (1 << 11) 47ed286ca5SPaul Burton 48ff1930c6SPaul Burton static struct ingenic_cgu *cgu; 49ff1930c6SPaul Burton 50ff1930c6SPaul Burton static const s8 pll_od_encoding[4] = { 51ff1930c6SPaul Burton 0x0, 0x1, -1, 0x3, 52ff1930c6SPaul Burton }; 53ff1930c6SPaul Burton 542a1a7036SPaul Cercueil static const u8 jz4740_cgu_cpccr_div_table[] = { 552a1a7036SPaul Cercueil 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 562a1a7036SPaul Cercueil }; 572a1a7036SPaul Cercueil 58568b9de4SPaul Cercueil static const u8 jz4740_cgu_pll_half_div_table[] = { 59568b9de4SPaul Cercueil 2, 1, 60568b9de4SPaul Cercueil }; 61568b9de4SPaul Cercueil 62ff1930c6SPaul Burton static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = { 63ff1930c6SPaul Burton 64ff1930c6SPaul Burton /* External clocks */ 65ff1930c6SPaul Burton 66ff1930c6SPaul Burton [JZ4740_CLK_EXT] = { "ext", CGU_CLK_EXT }, 67ff1930c6SPaul Burton [JZ4740_CLK_RTC] = { "rtc", CGU_CLK_EXT }, 68ff1930c6SPaul Burton 69ff1930c6SPaul Burton [JZ4740_CLK_PLL] = { 70ff1930c6SPaul Burton "pll", CGU_CLK_PLL, 71ff1930c6SPaul Burton .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, 72ff1930c6SPaul Burton .pll = { 73ff1930c6SPaul Burton .reg = CGU_REG_CPPCR, 749d9cc58aS周琰杰 (Zhou Yanjie) .rate_multiplier = 1, 75ff1930c6SPaul Burton .m_shift = 23, 76ff1930c6SPaul Burton .m_bits = 9, 77ff1930c6SPaul Burton .m_offset = 2, 78ff1930c6SPaul Burton .n_shift = 18, 79ff1930c6SPaul Burton .n_bits = 5, 80ff1930c6SPaul Burton .n_offset = 2, 81ff1930c6SPaul Burton .od_shift = 16, 82ff1930c6SPaul Burton .od_bits = 2, 83ff1930c6SPaul Burton .od_max = 4, 84ff1930c6SPaul Burton .od_encoding = pll_od_encoding, 85ff1930c6SPaul Burton .stable_bit = 10, 869d9cc58aS周琰杰 (Zhou Yanjie) .bypass_reg = CGU_REG_CPPCR, 87ff1930c6SPaul Burton .bypass_bit = 9, 88ff1930c6SPaul Burton .enable_bit = 8, 89ff1930c6SPaul Burton }, 90ff1930c6SPaul Burton }, 91ff1930c6SPaul Burton 92ff1930c6SPaul Burton /* Muxes & dividers */ 93ff1930c6SPaul Burton 94ff1930c6SPaul Burton [JZ4740_CLK_PLL_HALF] = { 95ff1930c6SPaul Burton "pll half", CGU_CLK_DIV, 96ff1930c6SPaul Burton .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, 97568b9de4SPaul Cercueil .div = { 98249592bfSPaul Cercueil CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1, 0, 99568b9de4SPaul Cercueil jz4740_cgu_pll_half_div_table, 100568b9de4SPaul Cercueil }, 101ff1930c6SPaul Burton }, 102ff1930c6SPaul Burton 103ff1930c6SPaul Burton [JZ4740_CLK_CCLK] = { 104ff1930c6SPaul Burton "cclk", CGU_CLK_DIV, 105*ca54d06fSAidan MacDonald /* 106*ca54d06fSAidan MacDonald * Disabling the CPU clock or any parent clocks will hang the 107*ca54d06fSAidan MacDonald * system; mark it critical. 108*ca54d06fSAidan MacDonald */ 109*ca54d06fSAidan MacDonald .flags = CLK_IS_CRITICAL, 110ff1930c6SPaul Burton .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, 1112a1a7036SPaul Cercueil .div = { 112249592bfSPaul Cercueil CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0, 1132a1a7036SPaul Cercueil jz4740_cgu_cpccr_div_table, 1142a1a7036SPaul Cercueil }, 115ff1930c6SPaul Burton }, 116ff1930c6SPaul Burton 117ff1930c6SPaul Burton [JZ4740_CLK_HCLK] = { 118ff1930c6SPaul Burton "hclk", CGU_CLK_DIV, 119ff1930c6SPaul Burton .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, 1202a1a7036SPaul Cercueil .div = { 121249592bfSPaul Cercueil CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0, 1222a1a7036SPaul Cercueil jz4740_cgu_cpccr_div_table, 1232a1a7036SPaul Cercueil }, 124ff1930c6SPaul Burton }, 125ff1930c6SPaul Burton 126ff1930c6SPaul Burton [JZ4740_CLK_PCLK] = { 127ff1930c6SPaul Burton "pclk", CGU_CLK_DIV, 128ff1930c6SPaul Burton .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, 1292a1a7036SPaul Cercueil .div = { 130249592bfSPaul Cercueil CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0, 1312a1a7036SPaul Cercueil jz4740_cgu_cpccr_div_table, 1322a1a7036SPaul Cercueil }, 133ff1930c6SPaul Burton }, 134ff1930c6SPaul Burton 135ff1930c6SPaul Burton [JZ4740_CLK_MCLK] = { 136ff1930c6SPaul Burton "mclk", CGU_CLK_DIV, 137*ca54d06fSAidan MacDonald /* 138*ca54d06fSAidan MacDonald * Disabling MCLK or its parents will render DRAM 139*ca54d06fSAidan MacDonald * inaccessible; mark it critical. 140*ca54d06fSAidan MacDonald */ 141*ca54d06fSAidan MacDonald .flags = CLK_IS_CRITICAL, 142ff1930c6SPaul Burton .parents = { JZ4740_CLK_PLL, -1, -1, -1 }, 1432a1a7036SPaul Cercueil .div = { 144249592bfSPaul Cercueil CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0, 1452a1a7036SPaul Cercueil jz4740_cgu_cpccr_div_table, 1462a1a7036SPaul Cercueil }, 147ff1930c6SPaul Burton }, 148ff1930c6SPaul Burton 149ff1930c6SPaul Burton [JZ4740_CLK_LCD] = { 150ff1930c6SPaul Burton "lcd", CGU_CLK_DIV | CGU_CLK_GATE, 151ff1930c6SPaul Burton .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 }, 1522a1a7036SPaul Cercueil .div = { 153249592bfSPaul Cercueil CGU_REG_CPCCR, 16, 1, 5, 22, -1, -1, 0, 1542a1a7036SPaul Cercueil jz4740_cgu_cpccr_div_table, 1552a1a7036SPaul Cercueil }, 156ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 10 }, 157ff1930c6SPaul Burton }, 158ff1930c6SPaul Burton 159ff1930c6SPaul Burton [JZ4740_CLK_LCD_PCLK] = { 160ff1930c6SPaul Burton "lcd_pclk", CGU_CLK_DIV, 161ff1930c6SPaul Burton .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 }, 1624afe2d1aSHarvey Hunt .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 }, 163ff1930c6SPaul Burton }, 164ff1930c6SPaul Burton 165ff1930c6SPaul Burton [JZ4740_CLK_I2S] = { 166ff1930c6SPaul Burton "i2s", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, 167ff1930c6SPaul Burton .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 }, 168ff1930c6SPaul Burton .mux = { CGU_REG_CPCCR, 31, 1 }, 169574f4e80SPaul Cercueil .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 }, 170ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 6 }, 171ff1930c6SPaul Burton }, 172ff1930c6SPaul Burton 173ff1930c6SPaul Burton [JZ4740_CLK_SPI] = { 174ff1930c6SPaul Burton "spi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, 175ff1930c6SPaul Burton .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL, -1, -1 }, 176ff1930c6SPaul Burton .mux = { CGU_REG_SSICDR, 31, 1 }, 1774afe2d1aSHarvey Hunt .div = { CGU_REG_SSICDR, 0, 1, 4, -1, -1, -1 }, 178ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 4 }, 179ff1930c6SPaul Burton }, 180ff1930c6SPaul Burton 181ff1930c6SPaul Burton [JZ4740_CLK_MMC] = { 182ff1930c6SPaul Burton "mmc", CGU_CLK_DIV | CGU_CLK_GATE, 183ff1930c6SPaul Burton .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 }, 1844afe2d1aSHarvey Hunt .div = { CGU_REG_MSCCDR, 0, 1, 5, -1, -1, -1 }, 185ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 7 }, 186ff1930c6SPaul Burton }, 187ff1930c6SPaul Burton 188ff1930c6SPaul Burton [JZ4740_CLK_UHC] = { 189ff1930c6SPaul Burton "uhc", CGU_CLK_DIV | CGU_CLK_GATE, 190ff1930c6SPaul Burton .parents = { JZ4740_CLK_PLL_HALF, -1, -1, -1 }, 1914afe2d1aSHarvey Hunt .div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 }, 192ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 14 }, 193ff1930c6SPaul Burton }, 194ff1930c6SPaul Burton 195ff1930c6SPaul Burton [JZ4740_CLK_UDC] = { 1962b555a4bSPaul Cercueil "udc", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, 197ff1930c6SPaul Burton .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 }, 198ff1930c6SPaul Burton .mux = { CGU_REG_CPCCR, 29, 1 }, 1994afe2d1aSHarvey Hunt .div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 }, 200b7e29924SPaul Cercueil .gate = { CGU_REG_SCR, 6, true }, 201ff1930c6SPaul Burton }, 202ff1930c6SPaul Burton 203ff1930c6SPaul Burton /* Gate-only clocks */ 204ff1930c6SPaul Burton 205ff1930c6SPaul Burton [JZ4740_CLK_UART0] = { 206ff1930c6SPaul Burton "uart0", CGU_CLK_GATE, 207ff1930c6SPaul Burton .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, 208ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 0 }, 209ff1930c6SPaul Burton }, 210ff1930c6SPaul Burton 211ff1930c6SPaul Burton [JZ4740_CLK_UART1] = { 212ff1930c6SPaul Burton "uart1", CGU_CLK_GATE, 213ff1930c6SPaul Burton .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, 214ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 15 }, 215ff1930c6SPaul Burton }, 216ff1930c6SPaul Burton 217ff1930c6SPaul Burton [JZ4740_CLK_DMA] = { 218ff1930c6SPaul Burton "dma", CGU_CLK_GATE, 219ff1930c6SPaul Burton .parents = { JZ4740_CLK_PCLK, -1, -1, -1 }, 220ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 12 }, 221ff1930c6SPaul Burton }, 222ff1930c6SPaul Burton 223ff1930c6SPaul Burton [JZ4740_CLK_IPU] = { 224ff1930c6SPaul Burton "ipu", CGU_CLK_GATE, 225ff1930c6SPaul Burton .parents = { JZ4740_CLK_PCLK, -1, -1, -1 }, 226ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 13 }, 227ff1930c6SPaul Burton }, 228ff1930c6SPaul Burton 229ff1930c6SPaul Burton [JZ4740_CLK_ADC] = { 230ff1930c6SPaul Burton "adc", CGU_CLK_GATE, 231ff1930c6SPaul Burton .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, 232ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 8 }, 233ff1930c6SPaul Burton }, 234ff1930c6SPaul Burton 235ff1930c6SPaul Burton [JZ4740_CLK_I2C] = { 236ff1930c6SPaul Burton "i2c", CGU_CLK_GATE, 237ff1930c6SPaul Burton .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, 238ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 3 }, 239ff1930c6SPaul Burton }, 240ff1930c6SPaul Burton 241ff1930c6SPaul Burton [JZ4740_CLK_AIC] = { 242ff1930c6SPaul Burton "aic", CGU_CLK_GATE, 243ff1930c6SPaul Burton .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, 244ff1930c6SPaul Burton .gate = { CGU_REG_CLKGR, 5 }, 245ff1930c6SPaul Burton }, 24673dd11dcSPaul Cercueil 24773dd11dcSPaul Cercueil [JZ4740_CLK_TCU] = { 24873dd11dcSPaul Cercueil "tcu", CGU_CLK_GATE, 24973dd11dcSPaul Cercueil .parents = { JZ4740_CLK_EXT, -1, -1, -1 }, 25073dd11dcSPaul Cercueil .gate = { CGU_REG_CLKGR, 1 }, 25173dd11dcSPaul Cercueil }, 252ff1930c6SPaul Burton }; 253ff1930c6SPaul Burton 254ff1930c6SPaul Burton static void __init jz4740_cgu_init(struct device_node *np) 255ff1930c6SPaul Burton { 256ff1930c6SPaul Burton int retval; 257ff1930c6SPaul Burton 258ff1930c6SPaul Burton cgu = ingenic_cgu_new(jz4740_cgu_clocks, 259ff1930c6SPaul Burton ARRAY_SIZE(jz4740_cgu_clocks), np); 260ff1930c6SPaul Burton if (!cgu) { 261ff1930c6SPaul Burton pr_err("%s: failed to initialise CGU\n", __func__); 262ff1930c6SPaul Burton return; 263ff1930c6SPaul Burton } 264ff1930c6SPaul Burton 265ff1930c6SPaul Burton retval = ingenic_cgu_register_clocks(cgu); 266ff1930c6SPaul Burton if (retval) 267ff1930c6SPaul Burton pr_err("%s: failed to register CGU Clocks\n", __func__); 2682ee93e3cSPaul Cercueil 2692ee93e3cSPaul Cercueil ingenic_cgu_register_syscore_ops(cgu); 270ff1930c6SPaul Burton } 27103d570e1SPaul Cercueil CLK_OF_DECLARE_DRIVER(jz4740_cgu, "ingenic,jz4740-cgu", jz4740_cgu_init); 272