Jacky Bai | c43a801 | 2021-09-14 14:52:07 +0800 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0+ |
| 2 | /* |
| 3 | * Copyright 2021 NXP |
| 4 | */ |
| 5 | |
| 6 | #include <dt-bindings/clock/imx8ulp-clock.h> |
| 7 | #include <linux/err.h> |
| 8 | #include <linux/io.h> |
| 9 | #include <linux/module.h> |
| 10 | #include <linux/of_device.h> |
| 11 | #include <linux/platform_device.h> |
Jacky Bai | 3fa3620 | 2021-09-14 14:52:08 +0800 | [diff] [blame] | 12 | #include <linux/reset-controller.h> |
Jacky Bai | c43a801 | 2021-09-14 14:52:07 +0800 | [diff] [blame] | 13 | #include <linux/slab.h> |
| 14 | |
| 15 | #include "clk.h" |
| 16 | |
| 17 | static const char * const pll_pre_sels[] = { "sosc", "frosc", }; |
| 18 | static const char * const a35_sels[] = { "frosc", "spll2", "sosc", "lvds", }; |
| 19 | static const char * const nic_sels[] = { "frosc", "spll3_pfd0", "sosc", "lvds", }; |
| 20 | static const char * const pcc3_periph_bus_sels[] = { "dummy", "lposc", "sosc_div2", |
| 21 | "frosc_div2", "xbar_divbus", "spll3_pfd1_div1", |
| 22 | "spll3_pfd0_div2", "spll3_pfd0_div1", }; |
| 23 | static const char * const pcc4_periph_bus_sels[] = { "dummy", "dummy", "lposc", |
| 24 | "sosc_div2", "frosc_div2", "xbar_divbus", |
| 25 | "spll3_vcodiv", "spll3_pfd0_div1", }; |
| 26 | static const char * const pcc4_periph_plat_sels[] = { "dummy", "sosc_div1", "frosc_div1", |
| 27 | "spll3_pfd3_div2", "spll3_pfd3_div1", |
| 28 | "spll3_pfd2_div2", "spll3_pfd2_div1", |
| 29 | "spll3_pfd1_div2", }; |
| 30 | static const char * const pcc5_periph_bus_sels[] = { "dummy", "dummy", "lposc", |
| 31 | "sosc_div2", "frosc_div2", "lpav_bus_clk", |
| 32 | "pll4_vcodiv", "pll4_pfd3_div1", }; |
| 33 | static const char * const pcc5_periph_plat_sels[] = { "dummy", "pll4_pfd3_div2", "pll4_pfd2_div2", |
| 34 | "pll4_pfd2_div1", "pll4_pfd1_div2", |
| 35 | "pll4_pfd1_div1", "pll4_pfd0_div2", |
| 36 | "pll4_pfd0_div1", }; |
| 37 | static const char * const hifi_sels[] = { "frosc", "pll4", "pll4_pfd0", "sosc", |
| 38 | "lvds", "dummy", "dummy", "dummy", }; |
| 39 | static const char * const ddr_sels[] = { "frosc", "pll4_pfd1", "sosc", "lvds", |
| 40 | "pll4", "pll4", "pll4", "pll4", }; |
| 41 | static const char * const lpav_sels[] = { "frosc", "pll4_pfd1", "sosc", "lvds", }; |
| 42 | static const char * const sai45_sels[] = { "spll3_pfd1_div1", "aud_clk1", "aud_clk2", "sosc", }; |
| 43 | static const char * const sai67_sels[] = { "spll1_pfd2_div", "spll3_pfd1_div1", "aud_clk0", "aud_clk1", "aud_clk2", "sosc", "dummy", "dummy", }; |
| 44 | static const char * const aud_clk1_sels[] = { "ext_aud_mclk2", "sai4_rx_bclk", "sai4_tx_bclk", "sai5_rx_bclk", "sai5_tx_bclk", "dummy", "dummy", "dummy", }; |
| 45 | static const char * const aud_clk2_sels[] = { "ext_aud_mclk3", "sai6_rx_bclk", "sai6_tx_bclk", "sai7_rx_bclk", "sai7_tx_bclk", "spdif_rx", "dummy", "dummy", }; |
| 46 | static const char * const enet_ts_sels[] = { "ext_rmii_clk", "ext_ts_clk", "rosc", "ext_aud_mclk", "sosc", "dummy", "dummy", "dummy"}; |
| 47 | static const char * const xbar_divbus[] = { "xbar_divbus" }; |
| 48 | static const char * const nic_per_divplat[] = { "nic_per_divplat" }; |
| 49 | static const char * const lpav_axi_div[] = { "lpav_axi_div" }; |
| 50 | static const char * const lpav_bus_div[] = { "lpav_bus_div" }; |
| 51 | |
Jacky Bai | 3fa3620 | 2021-09-14 14:52:08 +0800 | [diff] [blame] | 52 | struct pcc_reset_dev { |
| 53 | void __iomem *base; |
| 54 | struct reset_controller_dev rcdev; |
| 55 | const u32 *resets; |
| 56 | /* Set to imx_ccm_lock to protect register access shared with clock control */ |
| 57 | spinlock_t *lock; |
| 58 | }; |
| 59 | |
| 60 | #define PCC_SW_RST BIT(28) |
| 61 | #define to_pcc_reset_dev(_rcdev) container_of(_rcdev, struct pcc_reset_dev, rcdev) |
| 62 | |
| 63 | static const u32 pcc3_resets[] = { |
| 64 | 0xa8, 0xac, 0xc8, 0xcc, 0xd0, |
| 65 | 0xd4, 0xd8, 0xdc, 0xe0, 0xe4, |
| 66 | 0xe8, 0xec, 0xf0 |
| 67 | }; |
| 68 | |
| 69 | static const u32 pcc4_resets[] = { |
| 70 | 0x4, 0x8, 0xc, 0x10, 0x14, |
| 71 | 0x18, 0x1c, 0x20, 0x24, 0x34, |
| 72 | 0x38, 0x3c, 0x40, 0x44, 0x48, |
| 73 | 0x4c, 0x54 |
| 74 | }; |
| 75 | |
| 76 | static const u32 pcc5_resets[] = { |
| 77 | 0xa0, 0xa4, 0xa8, 0xac, 0xb0, |
| 78 | 0xb4, 0xbc, 0xc0, 0xc8, 0xcc, |
| 79 | 0xd0, 0xf0, 0xf4, 0xf8 |
| 80 | }; |
| 81 | |
| 82 | static int imx8ulp_pcc_assert(struct reset_controller_dev *rcdev, unsigned long id) |
| 83 | { |
| 84 | struct pcc_reset_dev *pcc_reset = to_pcc_reset_dev(rcdev); |
| 85 | u32 offset = pcc_reset->resets[id]; |
| 86 | unsigned long flags; |
| 87 | u32 val; |
| 88 | |
| 89 | spin_lock_irqsave(pcc_reset->lock, flags); |
| 90 | |
| 91 | val = readl(pcc_reset->base + offset); |
| 92 | val &= ~PCC_SW_RST; |
| 93 | writel(val, pcc_reset->base + offset); |
| 94 | |
| 95 | spin_unlock_irqrestore(pcc_reset->lock, flags); |
| 96 | |
| 97 | return 0; |
| 98 | } |
| 99 | |
| 100 | static int imx8ulp_pcc_deassert(struct reset_controller_dev *rcdev, unsigned long id) |
| 101 | { |
| 102 | struct pcc_reset_dev *pcc_reset = to_pcc_reset_dev(rcdev); |
| 103 | u32 offset = pcc_reset->resets[id]; |
| 104 | unsigned long flags; |
| 105 | u32 val; |
| 106 | |
| 107 | spin_lock_irqsave(pcc_reset->lock, flags); |
| 108 | |
| 109 | val = readl(pcc_reset->base + offset); |
| 110 | val |= PCC_SW_RST; |
| 111 | writel(val, pcc_reset->base + offset); |
| 112 | |
| 113 | spin_unlock_irqrestore(pcc_reset->lock, flags); |
| 114 | |
| 115 | return 0; |
| 116 | } |
| 117 | |
| 118 | static const struct reset_control_ops imx8ulp_pcc_reset_ops = { |
| 119 | .assert = imx8ulp_pcc_assert, |
| 120 | .deassert = imx8ulp_pcc_deassert, |
| 121 | }; |
| 122 | |
| 123 | static int imx8ulp_pcc_reset_init(struct platform_device *pdev, void __iomem *base, |
| 124 | const u32 *resets, unsigned int nr_resets) |
| 125 | { |
| 126 | struct device_node *np = pdev->dev.of_node; |
| 127 | struct device *dev = &pdev->dev; |
| 128 | struct pcc_reset_dev *pcc_reset; |
| 129 | |
| 130 | pcc_reset = devm_kzalloc(dev, sizeof(*pcc_reset), GFP_KERNEL); |
| 131 | if (!pcc_reset) |
| 132 | return -ENOMEM; |
| 133 | |
| 134 | pcc_reset->base = base; |
| 135 | pcc_reset->lock = &imx_ccm_lock; |
| 136 | pcc_reset->resets = resets; |
| 137 | pcc_reset->rcdev.owner = THIS_MODULE; |
| 138 | pcc_reset->rcdev.nr_resets = nr_resets; |
| 139 | pcc_reset->rcdev.ops = &imx8ulp_pcc_reset_ops; |
| 140 | pcc_reset->rcdev.of_node = np; |
| 141 | |
| 142 | return devm_reset_controller_register(dev, &pcc_reset->rcdev); |
| 143 | } |
| 144 | |
Jacky Bai | c43a801 | 2021-09-14 14:52:07 +0800 | [diff] [blame] | 145 | static int imx8ulp_clk_cgc1_init(struct platform_device *pdev) |
| 146 | { |
| 147 | struct device *dev = &pdev->dev; |
| 148 | struct clk_hw_onecell_data *clk_data; |
| 149 | struct clk_hw **clks; |
| 150 | void __iomem *base; |
| 151 | |
| 152 | clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, IMX8ULP_CLK_CGC1_END), |
| 153 | GFP_KERNEL); |
| 154 | if (!clk_data) |
| 155 | return -ENOMEM; |
| 156 | |
| 157 | clk_data->num = IMX8ULP_CLK_CGC1_END; |
| 158 | clks = clk_data->hws; |
| 159 | |
| 160 | clks[IMX8ULP_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0); |
| 161 | |
| 162 | /* CGC1 */ |
| 163 | base = devm_platform_ioremap_resource(pdev, 0); |
| 164 | if (WARN_ON(IS_ERR(base))) |
| 165 | return PTR_ERR(base); |
| 166 | |
| 167 | clks[IMX8ULP_CLK_SPLL2_PRE_SEL] = imx_clk_hw_mux_flags("spll2_pre_sel", base + 0x510, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE); |
| 168 | clks[IMX8ULP_CLK_SPLL3_PRE_SEL] = imx_clk_hw_mux_flags("spll3_pre_sel", base + 0x610, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE); |
| 169 | |
| 170 | clks[IMX8ULP_CLK_SPLL2] = imx_clk_hw_pllv4(IMX_PLLV4_IMX8ULP, "spll2", "spll2_pre_sel", base + 0x500); |
| 171 | clks[IMX8ULP_CLK_SPLL3] = imx_clk_hw_pllv4(IMX_PLLV4_IMX8ULP, "spll3", "spll3_pre_sel", base + 0x600); |
| 172 | clks[IMX8ULP_CLK_SPLL3_VCODIV] = imx_clk_hw_divider("spll3_vcodiv", "spll3", base + 0x604, 0, 6); |
| 173 | |
| 174 | clks[IMX8ULP_CLK_SPLL3_PFD0] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX8ULP, "spll3_pfd0", "spll3_vcodiv", base + 0x614, 0); |
| 175 | clks[IMX8ULP_CLK_SPLL3_PFD1] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX8ULP, "spll3_pfd1", "spll3_vcodiv", base + 0x614, 1); |
| 176 | clks[IMX8ULP_CLK_SPLL3_PFD2] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX8ULP, "spll3_pfd2", "spll3_vcodiv", base + 0x614, 2); |
| 177 | clks[IMX8ULP_CLK_SPLL3_PFD3] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX8ULP, "spll3_pfd3", "spll3_vcodiv", base + 0x614, 3); |
| 178 | |
| 179 | clks[IMX8ULP_CLK_SPLL3_PFD0_DIV1_GATE] = imx_clk_hw_gate_dis("spll3_pfd0_div1_gate", "spll3_pfd0", base + 0x608, 7); |
| 180 | clks[IMX8ULP_CLK_SPLL3_PFD0_DIV2_GATE] = imx_clk_hw_gate_dis("spll3_pfd0_div2_gate", "spll3_pfd0", base + 0x608, 15); |
| 181 | clks[IMX8ULP_CLK_SPLL3_PFD1_DIV1_GATE] = imx_clk_hw_gate_dis("spll3_pfd1_div1_gate", "spll3_pfd1", base + 0x608, 23); |
| 182 | clks[IMX8ULP_CLK_SPLL3_PFD1_DIV2_GATE] = imx_clk_hw_gate_dis("spll3_pfd1_div2_gate", "spll3_pfd1", base + 0x608, 31); |
| 183 | clks[IMX8ULP_CLK_SPLL3_PFD2_DIV1_GATE] = imx_clk_hw_gate_dis("spll3_pfd2_div1_gate", "spll3_pfd2", base + 0x60c, 7); |
| 184 | clks[IMX8ULP_CLK_SPLL3_PFD2_DIV2_GATE] = imx_clk_hw_gate_dis("spll3_pfd2_div2_gate", "spll3_pfd2", base + 0x60c, 15); |
| 185 | clks[IMX8ULP_CLK_SPLL3_PFD3_DIV1_GATE] = imx_clk_hw_gate_dis("spll3_pfd3_div1_gate", "spll3_pfd3", base + 0x60c, 23); |
| 186 | clks[IMX8ULP_CLK_SPLL3_PFD3_DIV2_GATE] = imx_clk_hw_gate_dis("spll3_pfd3_div2_gate", "spll3_pfd3", base + 0x60c, 31); |
| 187 | clks[IMX8ULP_CLK_SPLL3_PFD0_DIV1] = imx_clk_hw_divider("spll3_pfd0_div1", "spll3_pfd0_div1_gate", base + 0x608, 0, 6); |
| 188 | clks[IMX8ULP_CLK_SPLL3_PFD0_DIV2] = imx_clk_hw_divider("spll3_pfd0_div2", "spll3_pfd0_div2_gate", base + 0x608, 8, 6); |
| 189 | clks[IMX8ULP_CLK_SPLL3_PFD1_DIV1] = imx_clk_hw_divider("spll3_pfd1_div1", "spll3_pfd1_div1_gate", base + 0x608, 16, 6); |
| 190 | clks[IMX8ULP_CLK_SPLL3_PFD1_DIV2] = imx_clk_hw_divider("spll3_pfd1_div2", "spll3_pfd1_div2_gate", base + 0x608, 24, 6); |
| 191 | clks[IMX8ULP_CLK_SPLL3_PFD2_DIV1] = imx_clk_hw_divider("spll3_pfd2_div1", "spll3_pfd2_div1_gate", base + 0x60c, 0, 6); |
| 192 | clks[IMX8ULP_CLK_SPLL3_PFD2_DIV2] = imx_clk_hw_divider("spll3_pfd2_div2", "spll3_pfd2_div2_gate", base + 0x60c, 8, 6); |
| 193 | clks[IMX8ULP_CLK_SPLL3_PFD3_DIV1] = imx_clk_hw_divider("spll3_pfd3_div1", "spll3_pfd3_div1_gate", base + 0x60c, 16, 6); |
| 194 | clks[IMX8ULP_CLK_SPLL3_PFD3_DIV2] = imx_clk_hw_divider("spll3_pfd3_div2", "spll3_pfd3_div2_gate", base + 0x60c, 24, 6); |
| 195 | |
| 196 | clks[IMX8ULP_CLK_A35_SEL] = imx_clk_hw_mux2("a35_sel", base + 0x14, 28, 2, a35_sels, ARRAY_SIZE(a35_sels)); |
| 197 | clks[IMX8ULP_CLK_A35_DIV] = imx_clk_hw_divider_flags("a35_div", "a35_sel", base + 0x14, 21, 6, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); |
| 198 | |
| 199 | clks[IMX8ULP_CLK_NIC_SEL] = imx_clk_hw_mux2("nic_sel", base + 0x34, 28, 2, nic_sels, ARRAY_SIZE(nic_sels)); |
| 200 | clks[IMX8ULP_CLK_NIC_AD_DIVPLAT] = imx_clk_hw_divider_flags("nic_ad_divplat", "nic_sel", base + 0x34, 21, 6, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); |
| 201 | clks[IMX8ULP_CLK_NIC_PER_DIVPLAT] = imx_clk_hw_divider_flags("nic_per_divplat", "nic_ad_divplat", base + 0x34, 14, 6, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); |
| 202 | clks[IMX8ULP_CLK_XBAR_AD_DIVPLAT] = imx_clk_hw_divider_flags("xbar_ad_divplat", "nic_ad_divplat", base + 0x38, 14, 6, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); |
| 203 | clks[IMX8ULP_CLK_XBAR_DIVBUS] = imx_clk_hw_divider_flags("xbar_divbus", "nic_ad_divplat", base + 0x38, 7, 6, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); |
| 204 | clks[IMX8ULP_CLK_XBAR_AD_SLOW] = imx_clk_hw_divider_flags("xbar_ad_slow", "nic_ad_divplat", base + 0x38, 0, 6, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); |
| 205 | |
| 206 | clks[IMX8ULP_CLK_SOSC_DIV1_GATE] = imx_clk_hw_gate_dis("sosc_div1_gate", "sosc", base + 0x108, 7); |
| 207 | clks[IMX8ULP_CLK_SOSC_DIV2_GATE] = imx_clk_hw_gate_dis("sosc_div2_gate", "sosc", base + 0x108, 15); |
| 208 | clks[IMX8ULP_CLK_SOSC_DIV3_GATE] = imx_clk_hw_gate_dis("sosc_div3_gate", "sosc", base + 0x108, 23); |
| 209 | clks[IMX8ULP_CLK_SOSC_DIV1] = imx_clk_hw_divider("sosc_div1", "sosc_div1_gate", base + 0x108, 0, 6); |
| 210 | clks[IMX8ULP_CLK_SOSC_DIV2] = imx_clk_hw_divider("sosc_div2", "sosc_div2_gate", base + 0x108, 8, 6); |
| 211 | clks[IMX8ULP_CLK_SOSC_DIV3] = imx_clk_hw_divider("sosc_div3", "sosc_div3_gate", base + 0x108, 16, 6); |
| 212 | |
| 213 | clks[IMX8ULP_CLK_FROSC_DIV1_GATE] = imx_clk_hw_gate_dis("frosc_div1_gate", "frosc", base + 0x208, 7); |
| 214 | clks[IMX8ULP_CLK_FROSC_DIV2_GATE] = imx_clk_hw_gate_dis("frosc_div2_gate", "frosc", base + 0x208, 15); |
| 215 | clks[IMX8ULP_CLK_FROSC_DIV3_GATE] = imx_clk_hw_gate_dis("frosc_div3_gate", "frosc", base + 0x208, 23); |
| 216 | clks[IMX8ULP_CLK_FROSC_DIV1] = imx_clk_hw_divider("frosc_div1", "frosc_div1_gate", base + 0x208, 0, 6); |
| 217 | clks[IMX8ULP_CLK_FROSC_DIV2] = imx_clk_hw_divider("frosc_div2", "frosc_div2_gate", base + 0x208, 8, 6); |
| 218 | clks[IMX8ULP_CLK_FROSC_DIV3] = imx_clk_hw_divider("frosc_div3", "frosc_div3_gate", base + 0x208, 16, 6); |
| 219 | clks[IMX8ULP_CLK_AUD_CLK1] = imx_clk_hw_mux2("aud_clk1", base + 0x900, 0, 3, aud_clk1_sels, ARRAY_SIZE(aud_clk1_sels)); |
| 220 | clks[IMX8ULP_CLK_SAI4_SEL] = imx_clk_hw_mux2("sai4_sel", base + 0x904, 0, 2, sai45_sels, ARRAY_SIZE(sai45_sels)); |
| 221 | clks[IMX8ULP_CLK_SAI5_SEL] = imx_clk_hw_mux2("sai5_sel", base + 0x904, 8, 2, sai45_sels, ARRAY_SIZE(sai45_sels)); |
| 222 | clks[IMX8ULP_CLK_ENET_TS_SEL] = imx_clk_hw_mux2("enet_ts", base + 0x700, 24, 3, enet_ts_sels, ARRAY_SIZE(enet_ts_sels)); |
| 223 | |
| 224 | imx_check_clk_hws(clks, clk_data->num); |
| 225 | |
| 226 | return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data); |
| 227 | } |
| 228 | |
| 229 | static int imx8ulp_clk_cgc2_init(struct platform_device *pdev) |
| 230 | { |
| 231 | struct device *dev = &pdev->dev; |
| 232 | struct clk_hw_onecell_data *clk_data; |
| 233 | struct clk_hw **clks; |
| 234 | void __iomem *base; |
| 235 | |
| 236 | clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, IMX8ULP_CLK_CGC2_END), |
| 237 | GFP_KERNEL); |
| 238 | if (!clk_data) |
| 239 | return -ENOMEM; |
| 240 | |
| 241 | clk_data->num = IMX8ULP_CLK_CGC2_END; |
| 242 | clks = clk_data->hws; |
| 243 | |
| 244 | /* CGC2 */ |
| 245 | base = devm_platform_ioremap_resource(pdev, 0); |
| 246 | if (WARN_ON(IS_ERR(base))) |
| 247 | return PTR_ERR(base); |
| 248 | |
| 249 | clks[IMX8ULP_CLK_PLL4_PRE_SEL] = imx_clk_hw_mux_flags("pll4_pre_sel", base + 0x610, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE); |
| 250 | |
| 251 | clks[IMX8ULP_CLK_PLL4] = imx_clk_hw_pllv4(IMX_PLLV4_IMX8ULP, "pll4", "pll4_pre_sel", base + 0x600); |
| 252 | clks[IMX8ULP_CLK_PLL4_VCODIV] = imx_clk_hw_divider("pll4_vcodiv", "pll4", base + 0x604, 0, 6); |
| 253 | |
| 254 | clks[IMX8ULP_CLK_HIFI_SEL] = imx_clk_hw_mux_flags("hifi_sel", base + 0x14, 28, 3, hifi_sels, ARRAY_SIZE(hifi_sels), CLK_SET_PARENT_GATE); |
| 255 | clks[IMX8ULP_CLK_HIFI_DIVCORE] = imx_clk_hw_divider("hifi_core_div", "hifi_sel", base + 0x14, 21, 6); |
| 256 | clks[IMX8ULP_CLK_HIFI_DIVPLAT] = imx_clk_hw_divider("hifi_plat_div", "hifi_core_div", base + 0x14, 14, 6); |
| 257 | |
| 258 | clks[IMX8ULP_CLK_DDR_SEL] = imx_clk_hw_mux_flags("ddr_sel", base + 0x40, 28, 3, ddr_sels, ARRAY_SIZE(ddr_sels), CLK_SET_PARENT_GATE); |
| 259 | clks[IMX8ULP_CLK_DDR_DIV] = imx_clk_hw_divider_flags("ddr_div", "ddr_sel", base + 0x40, 21, 6, CLK_IS_CRITICAL); |
| 260 | clks[IMX8ULP_CLK_LPAV_AXI_SEL] = imx_clk_hw_mux("lpav_sel", base + 0x3c, 28, 2, lpav_sels, ARRAY_SIZE(lpav_sels)); |
| 261 | clks[IMX8ULP_CLK_LPAV_AXI_DIV] = imx_clk_hw_divider_flags("lpav_axi_div", "lpav_sel", base + 0x3c, 21, 6, CLK_IS_CRITICAL); |
| 262 | clks[IMX8ULP_CLK_LPAV_AHB_DIV] = imx_clk_hw_divider_flags("lpav_ahb_div", "lpav_axi_div", base + 0x3c, 14, 6, CLK_IS_CRITICAL); |
| 263 | clks[IMX8ULP_CLK_LPAV_BUS_DIV] = imx_clk_hw_divider_flags("lpav_bus_div", "lpav_axi_div", base + 0x3c, 7, 6, CLK_IS_CRITICAL); |
| 264 | |
| 265 | clks[IMX8ULP_CLK_PLL4_PFD0] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX8ULP, "pll4_pfd0", "pll4_vcodiv", base + 0x614, 0); |
| 266 | clks[IMX8ULP_CLK_PLL4_PFD1] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX8ULP, "pll4_pfd1", "pll4_vcodiv", base + 0x614, 1); |
| 267 | clks[IMX8ULP_CLK_PLL4_PFD2] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX8ULP, "pll4_pfd2", "pll4_vcodiv", base + 0x614, 2); |
| 268 | clks[IMX8ULP_CLK_PLL4_PFD3] = imx_clk_hw_pfdv2(IMX_PFDV2_IMX8ULP, "pll4_pfd3", "pll4_vcodiv", base + 0x614, 3); |
| 269 | |
| 270 | clks[IMX8ULP_CLK_PLL4_PFD0_DIV1_GATE] = imx_clk_hw_gate_dis("pll4_pfd0_div1_gate", "pll4_pfd0", base + 0x608, 7); |
| 271 | clks[IMX8ULP_CLK_PLL4_PFD0_DIV2_GATE] = imx_clk_hw_gate_dis("pll4_pfd0_div2_gate", "pll4_pfd0", base + 0x608, 15); |
| 272 | clks[IMX8ULP_CLK_PLL4_PFD1_DIV1_GATE] = imx_clk_hw_gate_dis("pll4_pfd1_div1_gate", "pll4_pfd1", base + 0x608, 23); |
| 273 | clks[IMX8ULP_CLK_PLL4_PFD1_DIV2_GATE] = imx_clk_hw_gate_dis("pll4_pfd1_div2_gate", "pll4_pfd1", base + 0x608, 31); |
| 274 | clks[IMX8ULP_CLK_PLL4_PFD2_DIV1_GATE] = imx_clk_hw_gate_dis("pll4_pfd2_div1_gate", "pll4_pfd2", base + 0x60c, 7); |
| 275 | clks[IMX8ULP_CLK_PLL4_PFD2_DIV2_GATE] = imx_clk_hw_gate_dis("pll4_pfd2_div2_gate", "pll4_pfd2", base + 0x60c, 15); |
| 276 | clks[IMX8ULP_CLK_PLL4_PFD3_DIV1_GATE] = imx_clk_hw_gate_dis("pll4_pfd3_div1_gate", "pll4_pfd3", base + 0x60c, 23); |
| 277 | clks[IMX8ULP_CLK_PLL4_PFD3_DIV2_GATE] = imx_clk_hw_gate_dis("pll4_pfd3_div2_gate", "pll4_pfd3", base + 0x60c, 31); |
| 278 | clks[IMX8ULP_CLK_PLL4_PFD0_DIV1] = imx_clk_hw_divider("pll4_pfd0_div1", "pll4_pfd0_div1_gate", base + 0x608, 0, 6); |
| 279 | clks[IMX8ULP_CLK_PLL4_PFD0_DIV2] = imx_clk_hw_divider("pll4_pfd0_div2", "pll4_pfd0_div2_gate", base + 0x608, 8, 6); |
| 280 | clks[IMX8ULP_CLK_PLL4_PFD1_DIV1] = imx_clk_hw_divider("pll4_pfd1_div1", "pll4_pfd1_div1_gate", base + 0x608, 16, 6); |
| 281 | clks[IMX8ULP_CLK_PLL4_PFD1_DIV2] = imx_clk_hw_divider("pll4_pfd1_div2", "pll4_pfd1_div2_gate", base + 0x608, 24, 6); |
| 282 | clks[IMX8ULP_CLK_PLL4_PFD2_DIV1] = imx_clk_hw_divider("pll4_pfd2_div1", "pll4_pfd2_div1_gate", base + 0x60c, 0, 6); |
| 283 | clks[IMX8ULP_CLK_PLL4_PFD2_DIV2] = imx_clk_hw_divider("pll4_pfd2_div2", "pll4_pfd2_div2_gate", base + 0x60c, 8, 6); |
| 284 | clks[IMX8ULP_CLK_PLL4_PFD3_DIV1] = imx_clk_hw_divider("pll4_pfd3_div1", "pll4_pfd3_div1_gate", base + 0x60c, 16, 6); |
| 285 | clks[IMX8ULP_CLK_PLL4_PFD3_DIV2] = imx_clk_hw_divider("pll4_pfd3_div2", "pll4_pfd3_div2_gate", base + 0x60c, 24, 6); |
| 286 | |
| 287 | clks[IMX8ULP_CLK_CGC2_SOSC_DIV1_GATE] = imx_clk_hw_gate_dis("cgc2_sosc_div1_gate", "sosc", base + 0x108, 7); |
| 288 | clks[IMX8ULP_CLK_CGC2_SOSC_DIV2_GATE] = imx_clk_hw_gate_dis("cgc2_sosc_div2_gate", "sosc", base + 0x108, 15); |
| 289 | clks[IMX8ULP_CLK_CGC2_SOSC_DIV3_GATE] = imx_clk_hw_gate_dis("cgc2_sosc_div3_gate", "sosc", base + 0x108, 23); |
| 290 | clks[IMX8ULP_CLK_CGC2_SOSC_DIV1] = imx_clk_hw_divider("cgc2_sosc_div1", "cgc2_sosc_div1_gate", base + 0x108, 0, 6); |
| 291 | clks[IMX8ULP_CLK_CGC2_SOSC_DIV2] = imx_clk_hw_divider("cgc2_sosc_div2", "cgc2_sosc_div2_gate", base + 0x108, 8, 6); |
| 292 | clks[IMX8ULP_CLK_CGC2_SOSC_DIV3] = imx_clk_hw_divider("cgc2_sosc_div3", "cgc2_sosc_div3_gate", base + 0x108, 16, 6); |
| 293 | |
| 294 | clks[IMX8ULP_CLK_CGC2_FROSC_DIV1_GATE] = imx_clk_hw_gate_dis("cgc2_frosc_div1_gate", "frosc", base + 0x208, 7); |
| 295 | clks[IMX8ULP_CLK_CGC2_FROSC_DIV2_GATE] = imx_clk_hw_gate_dis("cgc2_frosc_div2_gate", "frosc", base + 0x208, 15); |
| 296 | clks[IMX8ULP_CLK_CGC2_FROSC_DIV3_GATE] = imx_clk_hw_gate_dis("cgc2_frosc_div3_gate", "frosc", base + 0x208, 23); |
| 297 | clks[IMX8ULP_CLK_CGC2_FROSC_DIV1] = imx_clk_hw_divider("cgc2_frosc_div1", "cgc2_frosc_div1_gate", base + 0x208, 0, 6); |
| 298 | clks[IMX8ULP_CLK_CGC2_FROSC_DIV2] = imx_clk_hw_divider("cgc2_frosc_div2", "cgc2_frosc_div2_gate", base + 0x208, 8, 6); |
| 299 | clks[IMX8ULP_CLK_CGC2_FROSC_DIV3] = imx_clk_hw_divider("cgc2_frosc_div3", "cgc2_frosc_div3_gate", base + 0x208, 16, 6); |
| 300 | clks[IMX8ULP_CLK_AUD_CLK2] = imx_clk_hw_mux2("aud_clk2", base + 0x900, 0, 3, aud_clk2_sels, ARRAY_SIZE(aud_clk2_sels)); |
| 301 | clks[IMX8ULP_CLK_SAI6_SEL] = imx_clk_hw_mux2("sai6_sel", base + 0x904, 0, 3, sai67_sels, ARRAY_SIZE(sai67_sels)); |
| 302 | clks[IMX8ULP_CLK_SAI7_SEL] = imx_clk_hw_mux2("sai7_sel", base + 0x904, 8, 3, sai67_sels, ARRAY_SIZE(sai67_sels)); |
| 303 | clks[IMX8ULP_CLK_SPDIF_SEL] = imx_clk_hw_mux2("spdif_sel", base + 0x910, 0, 3, sai67_sels, ARRAY_SIZE(sai67_sels)); |
| 304 | clks[IMX8ULP_CLK_DSI_PHY_REF] = imx_clk_hw_fixed("dsi_phy_ref", 24000000); |
| 305 | |
| 306 | imx_check_clk_hws(clks, clk_data->num); |
| 307 | |
| 308 | return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data); |
| 309 | } |
| 310 | |
| 311 | static int imx8ulp_clk_pcc3_init(struct platform_device *pdev) |
| 312 | { |
| 313 | struct device *dev = &pdev->dev; |
| 314 | struct clk_hw_onecell_data *clk_data; |
| 315 | struct clk_hw **clks; |
| 316 | void __iomem *base; |
| 317 | int ret; |
| 318 | |
| 319 | clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, IMX8ULP_CLK_PCC3_END), |
| 320 | GFP_KERNEL); |
| 321 | if (!clk_data) |
| 322 | return -ENOMEM; |
| 323 | |
| 324 | clk_data->num = IMX8ULP_CLK_PCC3_END; |
| 325 | clks = clk_data->hws; |
| 326 | |
| 327 | /* PCC3 */ |
| 328 | base = devm_platform_ioremap_resource(pdev, 0); |
| 329 | if (WARN_ON(IS_ERR(base))) |
| 330 | return PTR_ERR(base); |
| 331 | |
| 332 | clks[IMX8ULP_CLK_WDOG3] = imx8ulp_clk_hw_composite("wdog3", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xa8, 1); |
| 333 | clks[IMX8ULP_CLK_WDOG4] = imx8ulp_clk_hw_composite("wdog4", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xac, 1); |
| 334 | clks[IMX8ULP_CLK_LPIT1] = imx8ulp_clk_hw_composite("lpit1", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xc8, 1); |
| 335 | clks[IMX8ULP_CLK_TPM4] = imx8ulp_clk_hw_composite("tpm4", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xcc, 1); |
| 336 | clks[IMX8ULP_CLK_TPM5] = imx8ulp_clk_hw_composite("tpm5", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xd0, 1); |
| 337 | clks[IMX8ULP_CLK_FLEXIO1] = imx8ulp_clk_hw_composite("flexio1", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xd4, 1); |
| 338 | clks[IMX8ULP_CLK_I3C2] = imx8ulp_clk_hw_composite("i3c2", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xd8, 1); |
| 339 | clks[IMX8ULP_CLK_LPI2C4] = imx8ulp_clk_hw_composite("lpi2c4", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xdc, 1); |
| 340 | clks[IMX8ULP_CLK_LPI2C5] = imx8ulp_clk_hw_composite("lpi2c5", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xe0, 1); |
| 341 | clks[IMX8ULP_CLK_LPUART4] = imx8ulp_clk_hw_composite("lpuart4", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xe4, 1); |
| 342 | clks[IMX8ULP_CLK_LPUART5] = imx8ulp_clk_hw_composite("lpuart5", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xe8, 1); |
| 343 | clks[IMX8ULP_CLK_LPSPI4] = imx8ulp_clk_hw_composite("lpspi4", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xec, 1); |
| 344 | clks[IMX8ULP_CLK_LPSPI5] = imx8ulp_clk_hw_composite("lpspi5", pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), true, true, true, base + 0xf0, 1); |
| 345 | |
| 346 | clks[IMX8ULP_CLK_DMA1_MP] = imx_clk_hw_gate("pcc_dma1_mp", "xbar_ad_divplat", base + 0x4, 30); |
| 347 | clks[IMX8ULP_CLK_DMA1_CH0] = imx_clk_hw_gate("pcc_dma1_ch0", "xbar_ad_divplat", base + 0x8, 30); |
| 348 | clks[IMX8ULP_CLK_DMA1_CH1] = imx_clk_hw_gate("pcc_dma1_ch1", "xbar_ad_divplat", base + 0xc, 30); |
| 349 | clks[IMX8ULP_CLK_DMA1_CH2] = imx_clk_hw_gate("pcc_dma1_ch2", "xbar_ad_divplat", base + 0x10, 30); |
| 350 | clks[IMX8ULP_CLK_DMA1_CH3] = imx_clk_hw_gate("pcc_dma1_ch3", "xbar_ad_divplat", base + 0x14, 30); |
| 351 | clks[IMX8ULP_CLK_DMA1_CH4] = imx_clk_hw_gate("pcc_dma1_ch4", "xbar_ad_divplat", base + 0x18, 30); |
| 352 | clks[IMX8ULP_CLK_DMA1_CH5] = imx_clk_hw_gate("pcc_dma1_ch5", "xbar_ad_divplat", base + 0x1c, 30); |
| 353 | clks[IMX8ULP_CLK_DMA1_CH6] = imx_clk_hw_gate("pcc_dma1_ch6", "xbar_ad_divplat", base + 0x20, 30); |
| 354 | clks[IMX8ULP_CLK_DMA1_CH7] = imx_clk_hw_gate("pcc_dma1_ch7", "xbar_ad_divplat", base + 0x24, 30); |
| 355 | clks[IMX8ULP_CLK_DMA1_CH8] = imx_clk_hw_gate("pcc_dma1_ch8", "xbar_ad_divplat", base + 0x28, 30); |
| 356 | clks[IMX8ULP_CLK_DMA1_CH9] = imx_clk_hw_gate("pcc_dma1_ch9", "xbar_ad_divplat", base + 0x2c, 30); |
| 357 | clks[IMX8ULP_CLK_DMA1_CH10] = imx_clk_hw_gate("pcc_dma1_ch10", "xbar_ad_divplat", base + 0x30, 30); |
| 358 | clks[IMX8ULP_CLK_DMA1_CH11] = imx_clk_hw_gate("pcc_dma1_ch11", "xbar_ad_divplat", base + 0x34, 30); |
| 359 | clks[IMX8ULP_CLK_DMA1_CH12] = imx_clk_hw_gate("pcc_dma1_ch12", "xbar_ad_divplat", base + 0x38, 30); |
| 360 | clks[IMX8ULP_CLK_DMA1_CH13] = imx_clk_hw_gate("pcc_dma1_ch13", "xbar_ad_divplat", base + 0x3c, 30); |
| 361 | clks[IMX8ULP_CLK_DMA1_CH14] = imx_clk_hw_gate("pcc_dma1_ch14", "xbar_ad_divplat", base + 0x40, 30); |
| 362 | clks[IMX8ULP_CLK_DMA1_CH15] = imx_clk_hw_gate("pcc_dma1_ch15", "xbar_ad_divplat", base + 0x44, 30); |
| 363 | clks[IMX8ULP_CLK_DMA1_CH16] = imx_clk_hw_gate("pcc_dma1_ch16", "xbar_ad_divplat", base + 0x48, 30); |
| 364 | clks[IMX8ULP_CLK_DMA1_CH17] = imx_clk_hw_gate("pcc_dma1_ch17", "xbar_ad_divplat", base + 0x4c, 30); |
| 365 | clks[IMX8ULP_CLK_DMA1_CH18] = imx_clk_hw_gate("pcc_dma1_ch18", "xbar_ad_divplat", base + 0x50, 30); |
| 366 | clks[IMX8ULP_CLK_DMA1_CH19] = imx_clk_hw_gate("pcc_dma1_ch19", "xbar_ad_divplat", base + 0x54, 30); |
| 367 | clks[IMX8ULP_CLK_DMA1_CH20] = imx_clk_hw_gate("pcc_dma1_ch20", "xbar_ad_divplat", base + 0x58, 30); |
| 368 | clks[IMX8ULP_CLK_DMA1_CH21] = imx_clk_hw_gate("pcc_dma1_ch21", "xbar_ad_divplat", base + 0x5c, 30); |
| 369 | clks[IMX8ULP_CLK_DMA1_CH22] = imx_clk_hw_gate("pcc_dma1_ch22", "xbar_ad_divplat", base + 0x60, 30); |
| 370 | clks[IMX8ULP_CLK_DMA1_CH23] = imx_clk_hw_gate("pcc_dma1_ch23", "xbar_ad_divplat", base + 0x64, 30); |
| 371 | clks[IMX8ULP_CLK_DMA1_CH24] = imx_clk_hw_gate("pcc_dma1_ch24", "xbar_ad_divplat", base + 0x68, 30); |
| 372 | clks[IMX8ULP_CLK_DMA1_CH25] = imx_clk_hw_gate("pcc_dma1_ch25", "xbar_ad_divplat", base + 0x6c, 30); |
| 373 | clks[IMX8ULP_CLK_DMA1_CH26] = imx_clk_hw_gate("pcc_dma1_ch26", "xbar_ad_divplat", base + 0x70, 30); |
| 374 | clks[IMX8ULP_CLK_DMA1_CH27] = imx_clk_hw_gate("pcc_dma1_ch27", "xbar_ad_divplat", base + 0x74, 30); |
| 375 | clks[IMX8ULP_CLK_DMA1_CH28] = imx_clk_hw_gate("pcc_dma1_ch28", "xbar_ad_divplat", base + 0x78, 30); |
| 376 | clks[IMX8ULP_CLK_DMA1_CH29] = imx_clk_hw_gate("pcc_dma1_ch29", "xbar_ad_divplat", base + 0x7c, 30); |
| 377 | clks[IMX8ULP_CLK_DMA1_CH30] = imx_clk_hw_gate("pcc_dma1_ch30", "xbar_ad_divplat", base + 0x80, 30); |
| 378 | clks[IMX8ULP_CLK_DMA1_CH31] = imx_clk_hw_gate("pcc_dma1_ch31", "xbar_ad_divplat", base + 0x84, 30); |
| 379 | clks[IMX8ULP_CLK_MU0_B] = imx_clk_hw_gate("mu0_b", "xbar_ad_divplat", base + 0x88, 30); |
| 380 | clks[IMX8ULP_CLK_MU3_A] = imx_clk_hw_gate("mu3_a", "xbar_ad_divplat", base + 0x8c, 30); |
| 381 | |
| 382 | imx_check_clk_hws(clks, clk_data->num); |
| 383 | |
| 384 | ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data); |
Jacky Bai | 3fa3620 | 2021-09-14 14:52:08 +0800 | [diff] [blame] | 385 | if (ret) |
| 386 | return ret; |
Jacky Bai | c43a801 | 2021-09-14 14:52:07 +0800 | [diff] [blame] | 387 | |
| 388 | imx_register_uart_clocks(1); |
| 389 | |
Jacky Bai | 3fa3620 | 2021-09-14 14:52:08 +0800 | [diff] [blame] | 390 | /* register the pcc3 reset controller */ |
| 391 | return imx8ulp_pcc_reset_init(pdev, base, pcc3_resets, ARRAY_SIZE(pcc3_resets)); |
Jacky Bai | c43a801 | 2021-09-14 14:52:07 +0800 | [diff] [blame] | 392 | } |
| 393 | |
| 394 | static int imx8ulp_clk_pcc4_init(struct platform_device *pdev) |
| 395 | { |
| 396 | struct device *dev = &pdev->dev; |
| 397 | struct clk_hw_onecell_data *clk_data; |
| 398 | struct clk_hw **clks; |
| 399 | void __iomem *base; |
Jacky Bai | 3fa3620 | 2021-09-14 14:52:08 +0800 | [diff] [blame] | 400 | int ret; |
Jacky Bai | c43a801 | 2021-09-14 14:52:07 +0800 | [diff] [blame] | 401 | |
| 402 | clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, IMX8ULP_CLK_PCC4_END), |
| 403 | GFP_KERNEL); |
| 404 | if (!clk_data) |
| 405 | return -ENOMEM; |
| 406 | |
| 407 | clk_data->num = IMX8ULP_CLK_PCC4_END; |
| 408 | clks = clk_data->hws; |
| 409 | |
| 410 | /* PCC4 */ |
| 411 | base = devm_platform_ioremap_resource(pdev, 0); |
| 412 | if (WARN_ON(IS_ERR(base))) |
| 413 | return PTR_ERR(base); |
| 414 | |
| 415 | clks[IMX8ULP_CLK_FLEXSPI2] = imx8ulp_clk_hw_composite("flexspi2", pcc4_periph_plat_sels, ARRAY_SIZE(pcc4_periph_plat_sels), true, true, true, base + 0x4, 1); |
| 416 | clks[IMX8ULP_CLK_TPM6] = imx8ulp_clk_hw_composite("tpm6", pcc4_periph_bus_sels, ARRAY_SIZE(pcc4_periph_bus_sels), true, true, true, base + 0x8, 1); |
| 417 | clks[IMX8ULP_CLK_TPM7] = imx8ulp_clk_hw_composite("tpm7", pcc4_periph_bus_sels, ARRAY_SIZE(pcc4_periph_bus_sels), true, true, true, base + 0xc, 1); |
| 418 | clks[IMX8ULP_CLK_LPI2C6] = imx8ulp_clk_hw_composite("lpi2c6", pcc4_periph_bus_sels, ARRAY_SIZE(pcc4_periph_bus_sels), true, true, true, base + 0x10, 1); |
| 419 | clks[IMX8ULP_CLK_LPI2C7] = imx8ulp_clk_hw_composite("lpi2c7", pcc4_periph_bus_sels, ARRAY_SIZE(pcc4_periph_bus_sels), true, true, true, base + 0x14, 1); |
| 420 | clks[IMX8ULP_CLK_LPUART6] = imx8ulp_clk_hw_composite("lpuart6", pcc4_periph_bus_sels, ARRAY_SIZE(pcc4_periph_bus_sels), true, true, true, base + 0x18, 1); |
| 421 | clks[IMX8ULP_CLK_LPUART7] = imx8ulp_clk_hw_composite("lpuart7", pcc4_periph_bus_sels, ARRAY_SIZE(pcc4_periph_bus_sels), true, true, true, base + 0x1c, 1); |
| 422 | clks[IMX8ULP_CLK_SAI4] = imx8ulp_clk_hw_composite("sai4", xbar_divbus, 1, false, false, true, base + 0x20, 1); /* sai ipg, NOT from sai sel */ |
| 423 | clks[IMX8ULP_CLK_SAI5] = imx8ulp_clk_hw_composite("sai5", xbar_divbus, 1, false, false, true, base + 0x24, 1); /* sai ipg */ |
| 424 | clks[IMX8ULP_CLK_PCTLE] = imx_clk_hw_gate("pctle", "xbar_divbus", base + 0x28, 30); |
| 425 | clks[IMX8ULP_CLK_PCTLF] = imx_clk_hw_gate("pctlf", "xbar_divbus", base + 0x2c, 30); |
| 426 | clks[IMX8ULP_CLK_USDHC0] = imx8ulp_clk_hw_composite("usdhc0", pcc4_periph_plat_sels, ARRAY_SIZE(pcc4_periph_plat_sels), true, false, true, base + 0x34, 1); |
| 427 | clks[IMX8ULP_CLK_USDHC1] = imx8ulp_clk_hw_composite("usdhc1", pcc4_periph_plat_sels, ARRAY_SIZE(pcc4_periph_plat_sels), true, false, true, base + 0x38, 1); |
| 428 | clks[IMX8ULP_CLK_USDHC2] = imx8ulp_clk_hw_composite("usdhc2", pcc4_periph_plat_sels, ARRAY_SIZE(pcc4_periph_plat_sels), true, false, true, base + 0x3c, 1); |
| 429 | clks[IMX8ULP_CLK_USB0] = imx8ulp_clk_hw_composite("usb0", nic_per_divplat, 1, false, false, true, base + 0x40, 1); |
| 430 | clks[IMX8ULP_CLK_USB0_PHY] = imx8ulp_clk_hw_composite("usb0_phy", xbar_divbus, 1, false, false, true, base + 0x44, 1); |
| 431 | clks[IMX8ULP_CLK_USB1] = imx8ulp_clk_hw_composite("usb1", nic_per_divplat, 1, false, false, true, base + 0x48, 1); |
| 432 | clks[IMX8ULP_CLK_USB1_PHY] = imx8ulp_clk_hw_composite("usb1_phy", xbar_divbus, 1, false, false, true, base + 0x4c, 1); |
| 433 | clks[IMX8ULP_CLK_USB_XBAR] = imx_clk_hw_gate("usb_xbar", "xbar_divbus", base + 0x50, 30); |
| 434 | clks[IMX8ULP_CLK_ENET] = imx8ulp_clk_hw_composite("enet", nic_per_divplat, 1, false, false, true, base + 0x54, 1); |
| 435 | clks[IMX8ULP_CLK_RGPIOE] = imx_clk_hw_gate("rgpioe", "nic_per_divplat", base + 0x78, 30); |
| 436 | clks[IMX8ULP_CLK_RGPIOF] = imx_clk_hw_gate("rgpiof", "nic_per_divplat", base + 0x7c, 30); |
| 437 | |
| 438 | imx_check_clk_hws(clks, clk_data->num); |
| 439 | |
Jacky Bai | 3fa3620 | 2021-09-14 14:52:08 +0800 | [diff] [blame] | 440 | ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data); |
| 441 | if (ret) |
| 442 | return ret; |
| 443 | |
| 444 | /* register the pcc4 reset controller */ |
| 445 | return imx8ulp_pcc_reset_init(pdev, base, pcc4_resets, ARRAY_SIZE(pcc4_resets)); |
| 446 | |
Jacky Bai | c43a801 | 2021-09-14 14:52:07 +0800 | [diff] [blame] | 447 | } |
| 448 | |
| 449 | static int imx8ulp_clk_pcc5_init(struct platform_device *pdev) |
| 450 | { |
| 451 | struct device *dev = &pdev->dev; |
| 452 | struct clk_hw_onecell_data *clk_data; |
| 453 | struct clk_hw **clks; |
| 454 | void __iomem *base; |
Jacky Bai | 3fa3620 | 2021-09-14 14:52:08 +0800 | [diff] [blame] | 455 | int ret; |
Jacky Bai | c43a801 | 2021-09-14 14:52:07 +0800 | [diff] [blame] | 456 | |
| 457 | clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, IMX8ULP_CLK_PCC5_END), |
| 458 | GFP_KERNEL); |
| 459 | if (!clk_data) |
| 460 | return -ENOMEM; |
| 461 | |
| 462 | clk_data->num = IMX8ULP_CLK_PCC5_END; |
| 463 | clks = clk_data->hws; |
| 464 | |
| 465 | /* PCC5 */ |
| 466 | base = devm_platform_ioremap_resource(pdev, 0); |
| 467 | if (WARN_ON(IS_ERR(base))) |
| 468 | return PTR_ERR(base); |
| 469 | |
| 470 | clks[IMX8ULP_CLK_DMA2_MP] = imx_clk_hw_gate("pcc_dma2_mp", "lpav_axi_div", base + 0x0, 30); |
| 471 | clks[IMX8ULP_CLK_DMA2_CH0] = imx_clk_hw_gate("pcc_dma2_ch0", "lpav_axi_div", base + 0x4, 30); |
| 472 | clks[IMX8ULP_CLK_DMA2_CH1] = imx_clk_hw_gate("pcc_dma2_ch1", "lpav_axi_div", base + 0x8, 30); |
| 473 | clks[IMX8ULP_CLK_DMA2_CH2] = imx_clk_hw_gate("pcc_dma2_ch2", "lpav_axi_div", base + 0xc, 30); |
| 474 | clks[IMX8ULP_CLK_DMA2_CH3] = imx_clk_hw_gate("pcc_dma2_ch3", "lpav_axi_div", base + 0x10, 30); |
| 475 | clks[IMX8ULP_CLK_DMA2_CH4] = imx_clk_hw_gate("pcc_dma2_ch4", "lpav_axi_div", base + 0x14, 30); |
| 476 | clks[IMX8ULP_CLK_DMA2_CH5] = imx_clk_hw_gate("pcc_dma2_ch5", "lpav_axi_div", base + 0x18, 30); |
| 477 | clks[IMX8ULP_CLK_DMA2_CH6] = imx_clk_hw_gate("pcc_dma2_ch6", "lpav_axi_div", base + 0x1c, 30); |
| 478 | clks[IMX8ULP_CLK_DMA2_CH7] = imx_clk_hw_gate("pcc_dma2_ch7", "lpav_axi_div", base + 0x20, 30); |
| 479 | clks[IMX8ULP_CLK_DMA2_CH8] = imx_clk_hw_gate("pcc_dma2_ch8", "lpav_axi_div", base + 0x24, 30); |
| 480 | clks[IMX8ULP_CLK_DMA2_CH9] = imx_clk_hw_gate("pcc_dma2_ch9", "lpav_axi_div", base + 0x28, 30); |
| 481 | clks[IMX8ULP_CLK_DMA2_CH10] = imx_clk_hw_gate("pcc_dma2_ch10", "lpav_axi_div", base + 0x2c, 30); |
| 482 | clks[IMX8ULP_CLK_DMA2_CH11] = imx_clk_hw_gate("pcc_dma2_ch11", "lpav_axi_div", base + 0x30, 30); |
| 483 | clks[IMX8ULP_CLK_DMA2_CH12] = imx_clk_hw_gate("pcc_dma2_ch12", "lpav_axi_div", base + 0x34, 30); |
| 484 | clks[IMX8ULP_CLK_DMA2_CH13] = imx_clk_hw_gate("pcc_dma2_ch13", "lpav_axi_div", base + 0x38, 30); |
| 485 | clks[IMX8ULP_CLK_DMA2_CH14] = imx_clk_hw_gate("pcc_dma2_ch14", "lpav_axi_div", base + 0x3c, 30); |
| 486 | clks[IMX8ULP_CLK_DMA2_CH15] = imx_clk_hw_gate("pcc_dma2_ch15", "lpav_axi_div", base + 0x40, 30); |
| 487 | clks[IMX8ULP_CLK_DMA2_CH16] = imx_clk_hw_gate("pcc_dma2_ch16", "lpav_axi_div", base + 0x44, 30); |
| 488 | clks[IMX8ULP_CLK_DMA2_CH17] = imx_clk_hw_gate("pcc_dma2_ch17", "lpav_axi_div", base + 0x48, 30); |
| 489 | clks[IMX8ULP_CLK_DMA2_CH18] = imx_clk_hw_gate("pcc_dma2_ch18", "lpav_axi_div", base + 0x4c, 30); |
| 490 | clks[IMX8ULP_CLK_DMA2_CH19] = imx_clk_hw_gate("pcc_dma2_ch19", "lpav_axi_div", base + 0x50, 30); |
| 491 | clks[IMX8ULP_CLK_DMA2_CH20] = imx_clk_hw_gate("pcc_dma2_ch20", "lpav_axi_div", base + 0x54, 30); |
| 492 | clks[IMX8ULP_CLK_DMA2_CH21] = imx_clk_hw_gate("pcc_dma2_ch21", "lpav_axi_div", base + 0x58, 30); |
| 493 | clks[IMX8ULP_CLK_DMA2_CH22] = imx_clk_hw_gate("pcc_dma2_ch22", "lpav_axi_div", base + 0x5c, 30); |
| 494 | clks[IMX8ULP_CLK_DMA2_CH23] = imx_clk_hw_gate("pcc_dma2_ch23", "lpav_axi_div", base + 0x60, 30); |
| 495 | clks[IMX8ULP_CLK_DMA2_CH24] = imx_clk_hw_gate("pcc_dma2_ch24", "lpav_axi_div", base + 0x64, 30); |
| 496 | clks[IMX8ULP_CLK_DMA2_CH25] = imx_clk_hw_gate("pcc_dma2_ch25", "lpav_axi_div", base + 0x68, 30); |
| 497 | clks[IMX8ULP_CLK_DMA2_CH26] = imx_clk_hw_gate("pcc_dma2_ch26", "lpav_axi_div", base + 0x6c, 30); |
| 498 | clks[IMX8ULP_CLK_DMA2_CH27] = imx_clk_hw_gate("pcc_dma2_ch27", "lpav_axi_div", base + 0x70, 30); |
| 499 | clks[IMX8ULP_CLK_DMA2_CH28] = imx_clk_hw_gate("pcc_dma2_ch28", "lpav_axi_div", base + 0x74, 30); |
| 500 | clks[IMX8ULP_CLK_DMA2_CH29] = imx_clk_hw_gate("pcc_dma2_ch29", "lpav_axi_div", base + 0x78, 30); |
| 501 | clks[IMX8ULP_CLK_DMA2_CH30] = imx_clk_hw_gate("pcc_dma2_ch30", "lpav_axi_div", base + 0x7c, 30); |
| 502 | clks[IMX8ULP_CLK_DMA2_CH31] = imx_clk_hw_gate("pcc_dma2_ch31", "lpav_axi_div", base + 0x80, 30); |
| 503 | |
| 504 | clks[IMX8ULP_CLK_AVD_SIM] = imx_clk_hw_gate("avd_sim", "lpav_bus_div", base + 0x94, 30); |
| 505 | clks[IMX8ULP_CLK_TPM8] = imx8ulp_clk_hw_composite("tpm8", pcc5_periph_bus_sels, ARRAY_SIZE(pcc5_periph_bus_sels), true, true, true, base + 0xa0, 1); |
| 506 | clks[IMX8ULP_CLK_MU2_B] = imx_clk_hw_gate("mu2_b", "lpav_bus_div", base + 0x84, 30); |
| 507 | clks[IMX8ULP_CLK_MU3_B] = imx_clk_hw_gate("mu3_b", "lpav_bus_div", base + 0x88, 30); |
| 508 | clks[IMX8ULP_CLK_SAI6] = imx8ulp_clk_hw_composite("sai6", lpav_bus_div, 1, false, false, true, base + 0xa4, 1); |
| 509 | clks[IMX8ULP_CLK_SAI7] = imx8ulp_clk_hw_composite("sai7", lpav_bus_div, 1, false, false, true, base + 0xa8, 1); |
| 510 | clks[IMX8ULP_CLK_SPDIF] = imx8ulp_clk_hw_composite("spdif", lpav_bus_div, 1, false, false, true, base + 0xac, 1); |
| 511 | clks[IMX8ULP_CLK_ISI] = imx8ulp_clk_hw_composite("isi", lpav_axi_div, 1, false, false, true, base + 0xb0, 1); |
| 512 | clks[IMX8ULP_CLK_CSI_REGS] = imx8ulp_clk_hw_composite("csi_regs", lpav_bus_div, 1, false, false, true, base + 0xb4, 1); |
| 513 | clks[IMX8ULP_CLK_CSI] = imx8ulp_clk_hw_composite("csi", pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), true, true, true, base + 0xbc, 1); |
| 514 | clks[IMX8ULP_CLK_DSI] = imx8ulp_clk_hw_composite("dsi", pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), true, true, true, base + 0xc0, 1); |
| 515 | clks[IMX8ULP_CLK_WDOG5] = imx8ulp_clk_hw_composite("wdog5", pcc5_periph_bus_sels, ARRAY_SIZE(pcc5_periph_bus_sels), true, true, true, base + 0xc8, 1); |
| 516 | clks[IMX8ULP_CLK_EPDC] = imx8ulp_clk_hw_composite("epdc", pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), true, true, true, base + 0xcc, 1); |
| 517 | clks[IMX8ULP_CLK_PXP] = imx8ulp_clk_hw_composite("pxp", lpav_axi_div, 1, false, false, true, base + 0xd0, 1); |
| 518 | clks[IMX8ULP_CLK_GPU2D] = imx8ulp_clk_hw_composite("gpu2d", pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), true, true, true, base + 0xf0, 1); |
| 519 | clks[IMX8ULP_CLK_GPU3D] = imx8ulp_clk_hw_composite("gpu3d", pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), true, true, true, base + 0xf4, 1); |
| 520 | clks[IMX8ULP_CLK_DC_NANO] = imx8ulp_clk_hw_composite("dc_nano", pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), true, true, true, base + 0xf8, 1); |
| 521 | clks[IMX8ULP_CLK_CSI_CLK_UI] = imx8ulp_clk_hw_composite("csi_clk_ui", pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), true, true, true, base + 0x10c, 1); |
| 522 | clks[IMX8ULP_CLK_CSI_CLK_ESC] = imx8ulp_clk_hw_composite("csi_clk_esc", pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), true, true, true, base + 0x110, 1); |
| 523 | clks[IMX8ULP_CLK_RGPIOD] = imx_clk_hw_gate("rgpiod", "lpav_axi_div", base + 0x114, 30); |
| 524 | clks[IMX8ULP_CLK_DSI_TX_ESC] = imx_clk_hw_fixed_factor("mipi_dsi_tx_esc", "dsi", 1, 4); |
| 525 | |
| 526 | imx_check_clk_hws(clks, clk_data->num); |
| 527 | |
Jacky Bai | 3fa3620 | 2021-09-14 14:52:08 +0800 | [diff] [blame] | 528 | ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data); |
| 529 | if (ret) |
| 530 | return ret; |
| 531 | |
| 532 | /* register the pcc5 reset controller */ |
| 533 | return imx8ulp_pcc_reset_init(pdev, base, pcc5_resets, ARRAY_SIZE(pcc5_resets)); |
Jacky Bai | c43a801 | 2021-09-14 14:52:07 +0800 | [diff] [blame] | 534 | } |
| 535 | |
| 536 | static int imx8ulp_clk_probe(struct platform_device *pdev) |
| 537 | { |
| 538 | int (*probe)(struct platform_device *pdev); |
| 539 | |
| 540 | probe = of_device_get_match_data(&pdev->dev); |
| 541 | |
| 542 | if (probe) |
| 543 | return probe(pdev); |
| 544 | |
| 545 | return 0; |
| 546 | } |
| 547 | |
| 548 | static const struct of_device_id imx8ulp_clk_dt_ids[] = { |
| 549 | { .compatible = "fsl,imx8ulp-pcc3", .data = imx8ulp_clk_pcc3_init }, |
| 550 | { .compatible = "fsl,imx8ulp-pcc4", .data = imx8ulp_clk_pcc4_init }, |
| 551 | { .compatible = "fsl,imx8ulp-pcc5", .data = imx8ulp_clk_pcc5_init }, |
| 552 | { .compatible = "fsl,imx8ulp-cgc2", .data = imx8ulp_clk_cgc2_init }, |
| 553 | { .compatible = "fsl,imx8ulp-cgc1", .data = imx8ulp_clk_cgc1_init }, |
| 554 | { /* sentinel */ }, |
| 555 | }; |
| 556 | MODULE_DEVICE_TABLE(of, imx8ulp_clk_dt_ids); |
| 557 | |
| 558 | static struct platform_driver imx8ulp_clk_driver = { |
| 559 | .probe = imx8ulp_clk_probe, |
| 560 | .driver = { |
| 561 | .name = KBUILD_MODNAME, |
Peng Fan | b5e29cf | 2021-10-22 21:15:13 +0800 | [diff] [blame] | 562 | .suppress_bind_attrs = true, |
Jacky Bai | c43a801 | 2021-09-14 14:52:07 +0800 | [diff] [blame] | 563 | .of_match_table = imx8ulp_clk_dt_ids, |
| 564 | }, |
| 565 | }; |
| 566 | module_platform_driver(imx8ulp_clk_driver); |
| 567 | |
| 568 | MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>"); |
| 569 | MODULE_DESCRIPTION("NXP i.MX8ULP clock driver"); |
| 570 | MODULE_LICENSE("GPL v2"); |