^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2018-2019 SiFive, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Wesley Terpstra
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Paul Walmsley
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * This program is free software; you can redistribute it and/or modify
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * it under the terms of the GNU General Public License version 2 as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * published by the Free Software Foundation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * This program is distributed in the hope that it will be useful,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * but WITHOUT ANY WARRANTY; without even the implied warranty of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * GNU General Public License for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * The FU540 PRCI implements clock and reset control for the SiFive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * FU540-C000 chip. This driver assumes that it has sole control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * over all PRCI resources.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * This driver is based on the PRCI driver written by Wesley Terpstra:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * https://github.com/riscv/riscv-linux/commit/999529edf517ed75b56659d456d221b2ee56bb60
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * References:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * - SiFive FU540-C000 manual v1p0, Chapter 7 "Clocking and Reset"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <dt-bindings/clock/sifive-fu540-prci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/clkdev.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/clk-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/clk/analogbits-wrpll-cln28hpc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <linux/of_clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * hfclk and rtcclk
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define EXPECTED_CLK_PARENT_COUNT 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * Register offsets and bitmasks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) /* COREPLLCFG0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define PRCI_COREPLLCFG0_OFFSET 0x4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) # define PRCI_COREPLLCFG0_DIVR_SHIFT 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) # define PRCI_COREPLLCFG0_DIVR_MASK (0x3f << PRCI_COREPLLCFG0_DIVR_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) # define PRCI_COREPLLCFG0_DIVF_SHIFT 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) # define PRCI_COREPLLCFG0_DIVF_MASK (0x1ff << PRCI_COREPLLCFG0_DIVF_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) # define PRCI_COREPLLCFG0_DIVQ_SHIFT 15
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) # define PRCI_COREPLLCFG0_DIVQ_MASK (0x7 << PRCI_COREPLLCFG0_DIVQ_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) # define PRCI_COREPLLCFG0_RANGE_SHIFT 18
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) # define PRCI_COREPLLCFG0_RANGE_MASK (0x7 << PRCI_COREPLLCFG0_RANGE_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) # define PRCI_COREPLLCFG0_BYPASS_SHIFT 24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) # define PRCI_COREPLLCFG0_BYPASS_MASK (0x1 << PRCI_COREPLLCFG0_BYPASS_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) # define PRCI_COREPLLCFG0_FSE_SHIFT 25
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) # define PRCI_COREPLLCFG0_FSE_MASK (0x1 << PRCI_COREPLLCFG0_FSE_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) # define PRCI_COREPLLCFG0_LOCK_SHIFT 31
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) # define PRCI_COREPLLCFG0_LOCK_MASK (0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) /* DDRPLLCFG0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define PRCI_DDRPLLCFG0_OFFSET 0xc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) # define PRCI_DDRPLLCFG0_DIVR_SHIFT 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) # define PRCI_DDRPLLCFG0_DIVR_MASK (0x3f << PRCI_DDRPLLCFG0_DIVR_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) # define PRCI_DDRPLLCFG0_DIVF_SHIFT 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) # define PRCI_DDRPLLCFG0_DIVF_MASK (0x1ff << PRCI_DDRPLLCFG0_DIVF_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) # define PRCI_DDRPLLCFG0_DIVQ_SHIFT 15
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) # define PRCI_DDRPLLCFG0_DIVQ_MASK (0x7 << PRCI_DDRPLLCFG0_DIVQ_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) # define PRCI_DDRPLLCFG0_RANGE_SHIFT 18
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) # define PRCI_DDRPLLCFG0_RANGE_MASK (0x7 << PRCI_DDRPLLCFG0_RANGE_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) # define PRCI_DDRPLLCFG0_BYPASS_SHIFT 24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) # define PRCI_DDRPLLCFG0_BYPASS_MASK (0x1 << PRCI_DDRPLLCFG0_BYPASS_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) # define PRCI_DDRPLLCFG0_FSE_SHIFT 25
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) # define PRCI_DDRPLLCFG0_FSE_MASK (0x1 << PRCI_DDRPLLCFG0_FSE_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) # define PRCI_DDRPLLCFG0_LOCK_SHIFT 31
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) # define PRCI_DDRPLLCFG0_LOCK_MASK (0x1 << PRCI_DDRPLLCFG0_LOCK_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) /* DDRPLLCFG1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #define PRCI_DDRPLLCFG1_OFFSET 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) # define PRCI_DDRPLLCFG1_CKE_SHIFT 24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) # define PRCI_DDRPLLCFG1_CKE_MASK (0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) /* GEMGXLPLLCFG0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) #define PRCI_GEMGXLPLLCFG0_OFFSET 0x1c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) # define PRCI_GEMGXLPLLCFG0_DIVR_SHIFT 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) # define PRCI_GEMGXLPLLCFG0_DIVR_MASK (0x3f << PRCI_GEMGXLPLLCFG0_DIVR_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) # define PRCI_GEMGXLPLLCFG0_DIVF_SHIFT 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) # define PRCI_GEMGXLPLLCFG0_DIVF_MASK (0x1ff << PRCI_GEMGXLPLLCFG0_DIVF_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) # define PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT 15
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) # define PRCI_GEMGXLPLLCFG0_DIVQ_MASK (0x7 << PRCI_GEMGXLPLLCFG0_DIVQ_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) # define PRCI_GEMGXLPLLCFG0_RANGE_SHIFT 18
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) # define PRCI_GEMGXLPLLCFG0_RANGE_MASK (0x7 << PRCI_GEMGXLPLLCFG0_RANGE_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) # define PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT 24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) # define PRCI_GEMGXLPLLCFG0_BYPASS_MASK (0x1 << PRCI_GEMGXLPLLCFG0_BYPASS_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) # define PRCI_GEMGXLPLLCFG0_FSE_SHIFT 25
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) # define PRCI_GEMGXLPLLCFG0_FSE_MASK (0x1 << PRCI_GEMGXLPLLCFG0_FSE_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) # define PRCI_GEMGXLPLLCFG0_LOCK_SHIFT 31
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) # define PRCI_GEMGXLPLLCFG0_LOCK_MASK (0x1 << PRCI_GEMGXLPLLCFG0_LOCK_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) /* GEMGXLPLLCFG1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) #define PRCI_GEMGXLPLLCFG1_OFFSET 0x20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) # define PRCI_GEMGXLPLLCFG1_CKE_SHIFT 24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) # define PRCI_GEMGXLPLLCFG1_CKE_MASK (0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) /* CORECLKSEL */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) #define PRCI_CORECLKSEL_OFFSET 0x24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) # define PRCI_CORECLKSEL_CORECLKSEL_SHIFT 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) # define PRCI_CORECLKSEL_CORECLKSEL_MASK (0x1 << PRCI_CORECLKSEL_CORECLKSEL_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /* DEVICESRESETREG */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) #define PRCI_DEVICESRESETREG_OFFSET 0x28
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) # define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) # define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) # define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) # define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) # define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) # define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) # define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) # define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) # define PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT 5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) # define PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK (0x1 << PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) /* CLKMUXSTATUSREG */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) #define PRCI_CLKMUXSTATUSREG_OFFSET 0x2c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) # define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) # define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK (0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) * Private structures
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * struct __prci_data - per-device-instance data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) * @va: base virtual address of the PRCI IP block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * @hw_clks: encapsulates struct clk_hw records
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) * PRCI per-device instance data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) struct __prci_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) void __iomem *va;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) struct clk_hw_onecell_data hw_clks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) * struct __prci_wrpll_data - WRPLL configuration and integration data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) * @c: WRPLL current configuration record
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) * @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * @enable_bypass and @disable_bypass are used for WRPLL instances
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) * that contain a separate external glitchless clock mux downstream
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) * from the PLL. The WRPLL internal bypass mux is not glitchless.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) struct __prci_wrpll_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) struct wrpll_cfg c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) void (*enable_bypass)(struct __prci_data *pd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) void (*disable_bypass)(struct __prci_data *pd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) u8 cfg0_offs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * struct __prci_clock - describes a clock device managed by PRCI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) * @name: user-readable clock name string - should match the manual
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) * @parent_name: parent name for this clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) * @ops: struct clk_ops for the Linux clock framework to use for control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) * @hw: Linux-private clock data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) * @pwd: WRPLL-specific data, associated with this clock (if not NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) * @pd: PRCI-specific data associated with this clock (if not NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) * PRCI clock data. Used by the PRCI driver to register PRCI-provided
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) * clocks to the Linux clock infrastructure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) struct __prci_clock {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) const char *parent_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) const struct clk_ops *ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) struct clk_hw hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) struct __prci_wrpll_data *pwd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) struct __prci_data *pd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) #define clk_hw_to_prci_clock(pwd) container_of(pwd, struct __prci_clock, hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) * Private functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) * __prci_readl() - read from a PRCI register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) * @pd: PRCI context
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) * @offs: register offset to read from (in bytes, from PRCI base address)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) * Read the register located at offset @offs from the base virtual
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) * address of the PRCI register target described by @pd, and return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) * the value to the caller.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) * Context: Any context.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) * Return: the contents of the register described by @pd and @offs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) static u32 __prci_readl(struct __prci_data *pd, u32 offs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) return readl_relaxed(pd->va + offs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) writel_relaxed(v, pd->va + offs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) /* WRPLL-related private functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) * __prci_wrpll_unpack() - unpack WRPLL configuration registers into parameters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) * @c: ptr to a struct wrpll_cfg record to write config into
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) * @r: value read from the PRCI PLL configuration register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) * Given a value @r read from an FU540 PRCI PLL configuration register,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) * split it into fields and populate it into the WRPLL configuration record
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) * pointed to by @c.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) * The COREPLLCFG0 macros are used below, but the other *PLLCFG0 macros
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) * have the same register layout.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) * Context: Any context.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) static void __prci_wrpll_unpack(struct wrpll_cfg *c, u32 r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) u32 v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) v = r & PRCI_COREPLLCFG0_DIVR_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) v >>= PRCI_COREPLLCFG0_DIVR_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) c->divr = v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) v = r & PRCI_COREPLLCFG0_DIVF_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) v >>= PRCI_COREPLLCFG0_DIVF_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) c->divf = v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) v = r & PRCI_COREPLLCFG0_DIVQ_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) v >>= PRCI_COREPLLCFG0_DIVQ_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) c->divq = v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) v = r & PRCI_COREPLLCFG0_RANGE_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) v >>= PRCI_COREPLLCFG0_RANGE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) c->range = v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) c->flags &= (WRPLL_FLAGS_INT_FEEDBACK_MASK |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) WRPLL_FLAGS_EXT_FEEDBACK_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) /* external feedback mode not supported */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) * __prci_wrpll_pack() - pack PLL configuration parameters into a register value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) * @c: pointer to a struct wrpll_cfg record containing the PLL's cfg
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) * Using a set of WRPLL configuration values pointed to by @c,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) * assemble a PRCI PLL configuration register value, and return it to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) * the caller.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) * Context: Any context. Caller must ensure that the contents of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) * record pointed to by @c do not change during the execution
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) * of this function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) * Returns: a value suitable for writing into a PRCI PLL configuration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) * register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) static u32 __prci_wrpll_pack(const struct wrpll_cfg *c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) u32 r = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) r |= c->divr << PRCI_COREPLLCFG0_DIVR_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) r |= c->divf << PRCI_COREPLLCFG0_DIVF_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) r |= c->range << PRCI_COREPLLCFG0_RANGE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) /* external feedback mode not supported */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) r |= PRCI_COREPLLCFG0_FSE_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) * __prci_wrpll_read_cfg() - read the WRPLL configuration from the PRCI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) * @pd: PRCI context
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) * @pwd: PRCI WRPLL metadata
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) * Read the current configuration of the PLL identified by @pwd from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) * the PRCI identified by @pd, and store it into the local configuration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) * cache in @pwd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) * Context: Any context. Caller must prevent the records pointed to by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) * @pd and @pwd from changing during execution.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) static void __prci_wrpll_read_cfg(struct __prci_data *pd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) struct __prci_wrpll_data *pwd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) __prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) * __prci_wrpll_write_cfg() - write WRPLL configuration into the PRCI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) * @pd: PRCI context
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) * @pwd: PRCI WRPLL metadata
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) * @c: WRPLL configuration record to write
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) * Write the WRPLL configuration described by @c into the WRPLL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) * configuration register identified by @pwd in the PRCI instance
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) * described by @c. Make a cached copy of the WRPLL's current
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) * configuration so it can be used by other code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) * Context: Any context. Caller must prevent the records pointed to by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) * @pd and @pwd from changing during execution.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) static void __prci_wrpll_write_cfg(struct __prci_data *pd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) struct __prci_wrpll_data *pwd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) struct wrpll_cfg *c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) __prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) memcpy(&pwd->c, c, sizeof(*c));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) /* Core clock mux control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) * __prci_coreclksel_use_hfclk() - switch the CORECLK mux to output HFCLK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) * Switch the CORECLK mux to the HFCLK input source; return once complete.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) * Context: Any context. Caller must prevent concurrent changes to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) * PRCI_CORECLKSEL_OFFSET register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) static void __prci_coreclksel_use_hfclk(struct __prci_data *pd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) u32 r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) r |= PRCI_CORECLKSEL_CORECLKSEL_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) * __prci_coreclksel_use_corepll() - switch the CORECLK mux to output COREPLL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) * Switch the CORECLK mux to the PLL output clock; return once complete.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) * Context: Any context. Caller must prevent concurrent changes to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) * PRCI_CORECLKSEL_OFFSET register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) static void __prci_coreclksel_use_corepll(struct __prci_data *pd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) u32 r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) * Linux clock framework integration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) * See the Linux clock framework documentation for more information on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) * these functions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) static unsigned long sifive_fu540_prci_wrpll_recalc_rate(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) struct __prci_wrpll_data *pwd = pc->pwd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) return wrpll_calc_output_rate(&pwd->c, parent_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) static long sifive_fu540_prci_wrpll_round_rate(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) unsigned long *parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) struct __prci_wrpll_data *pwd = pc->pwd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) struct wrpll_cfg c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) memcpy(&c, &pwd->c, sizeof(c));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) wrpll_configure_for_rate(&c, rate, *parent_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) return wrpll_calc_output_rate(&c, *parent_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) static int sifive_fu540_prci_wrpll_set_rate(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) struct __prci_wrpll_data *pwd = pc->pwd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) struct __prci_data *pd = pc->pd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) r = wrpll_configure_for_rate(&pwd->c, rate, parent_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) if (r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) if (pwd->enable_bypass)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) pwd->enable_bypass(pd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) __prci_wrpll_write_cfg(pd, pwd, &pwd->c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) udelay(wrpll_calc_max_lock_us(&pwd->c));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) if (pwd->disable_bypass)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) pwd->disable_bypass(pd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) static const struct clk_ops sifive_fu540_prci_wrpll_clk_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) .set_rate = sifive_fu540_prci_wrpll_set_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) .round_rate = sifive_fu540_prci_wrpll_round_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) .recalc_rate = sifive_fu540_prci_wrpll_recalc_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) static const struct clk_ops sifive_fu540_prci_wrpll_ro_clk_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) .recalc_rate = sifive_fu540_prci_wrpll_recalc_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) /* TLCLKSEL clock integration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) static unsigned long sifive_fu540_prci_tlclksel_recalc_rate(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) struct __prci_data *pd = pc->pd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) u32 v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) u8 div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) v = __prci_readl(pd, PRCI_CLKMUXSTATUSREG_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) v &= PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) div = v ? 1 : 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) return div_u64(parent_rate, div);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) static const struct clk_ops sifive_fu540_prci_tlclksel_clk_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) .recalc_rate = sifive_fu540_prci_tlclksel_recalc_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) * PRCI integration data for each WRPLL instance
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) static struct __prci_wrpll_data __prci_corepll_data = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) .cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) .enable_bypass = __prci_coreclksel_use_hfclk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) .disable_bypass = __prci_coreclksel_use_corepll,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) static struct __prci_wrpll_data __prci_ddrpll_data = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) .cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) static struct __prci_wrpll_data __prci_gemgxlpll_data = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) .cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) * List of clock controls provided by the PRCI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) static struct __prci_clock __prci_init_clocks[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) [PRCI_CLK_COREPLL] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) .name = "corepll",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) .parent_name = "hfclk",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) .ops = &sifive_fu540_prci_wrpll_clk_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) .pwd = &__prci_corepll_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) [PRCI_CLK_DDRPLL] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) .name = "ddrpll",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) .parent_name = "hfclk",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) .ops = &sifive_fu540_prci_wrpll_ro_clk_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) .pwd = &__prci_ddrpll_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) [PRCI_CLK_GEMGXLPLL] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) .name = "gemgxlpll",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) .parent_name = "hfclk",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) .ops = &sifive_fu540_prci_wrpll_clk_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) .pwd = &__prci_gemgxlpll_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) [PRCI_CLK_TLCLK] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) .name = "tlclk",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) .parent_name = "corepll",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) .ops = &sifive_fu540_prci_tlclksel_clk_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) * __prci_register_clocks() - register clock controls in the PRCI with Linux
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) * @dev: Linux struct device *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) * Register the list of clock controls described in __prci_init_plls[] with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) * the Linux clock framework.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) * Return: 0 upon success or a negative error code upon failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) static int __prci_register_clocks(struct device *dev, struct __prci_data *pd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) struct clk_init_data init = { };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) struct __prci_clock *pic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) int parent_count, i, r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) parent_count = of_clk_get_parent_count(dev->of_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) if (parent_count != EXPECTED_CLK_PARENT_COUNT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) dev_err(dev, "expected only two parent clocks, found %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) parent_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) /* Register PLLs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) for (i = 0; i < ARRAY_SIZE(__prci_init_clocks); ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) pic = &__prci_init_clocks[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) init.name = pic->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) init.parent_names = &pic->parent_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) init.num_parents = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) init.ops = pic->ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) pic->hw.init = &init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) pic->pd = pd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) if (pic->pwd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) __prci_wrpll_read_cfg(pd, pic->pwd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) r = devm_clk_hw_register(dev, &pic->hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) if (r) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) dev_warn(dev, "Failed to register clock %s: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) init.name, r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) r = clk_hw_register_clkdev(&pic->hw, pic->name, dev_name(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) if (r) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) dev_warn(dev, "Failed to register clkdev for %s: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) init.name, r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) pd->hw_clks.hws[i] = &pic->hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) pd->hw_clks.num = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) r = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) &pd->hw_clks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) if (r) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) dev_err(dev, "could not add hw_provider: %d\n", r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) * Linux device model integration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) * See the Linux device model documentation for more information about
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) * these functions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) static int sifive_fu540_prci_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) struct __prci_data *pd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) pd = devm_kzalloc(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) struct_size(pd, hw_clks.hws,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) ARRAY_SIZE(__prci_init_clocks)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) if (!pd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) pd->va = devm_ioremap_resource(dev, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) if (IS_ERR(pd->va))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) return PTR_ERR(pd->va);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) r = __prci_register_clocks(dev, pd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) if (r) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) dev_err(dev, "could not register clocks: %d\n", r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) dev_dbg(dev, "SiFive FU540 PRCI probed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) static const struct of_device_id sifive_fu540_prci_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) { .compatible = "sifive,fu540-c000-prci", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) MODULE_DEVICE_TABLE(of, sifive_fu540_prci_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) static struct platform_driver sifive_fu540_prci_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) .name = "sifive-fu540-prci",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) .of_match_table = sifive_fu540_prci_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) .probe = sifive_fu540_prci_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) static int __init sifive_fu540_prci_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) return platform_driver_register(&sifive_fu540_prci_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) core_initcall(sifive_fu540_prci_init);