1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2016 Chen-Yu Tsai. All rights reserved. 4 */ 5 6 #include <linux/clk.h> 7 #include <linux/clk-provider.h> 8 #include <linux/module.h> 9 #include <linux/platform_device.h> 10 #include <linux/reset.h> 11 12 #include "ccu_common.h" 13 #include "ccu_div.h" 14 #include "ccu_gate.h" 15 #include "ccu_reset.h" 16 17 #include "ccu-sun9i-a80-de.h" 18 19 static SUNXI_CCU_GATE(fe0_clk, "fe0", "fe0-div", 20 0x00, BIT(0), 0); 21 static SUNXI_CCU_GATE(fe1_clk, "fe1", "fe1-div", 22 0x00, BIT(1), 0); 23 static SUNXI_CCU_GATE(fe2_clk, "fe2", "fe2-div", 24 0x00, BIT(2), 0); 25 static SUNXI_CCU_GATE(iep_deu0_clk, "iep-deu0", "de", 26 0x00, BIT(4), 0); 27 static SUNXI_CCU_GATE(iep_deu1_clk, "iep-deu1", "de", 28 0x00, BIT(5), 0); 29 static SUNXI_CCU_GATE(be0_clk, "be0", "be0-div", 30 0x00, BIT(8), 0); 31 static SUNXI_CCU_GATE(be1_clk, "be1", "be1-div", 32 0x00, BIT(9), 0); 33 static SUNXI_CCU_GATE(be2_clk, "be2", "be2-div", 34 0x00, BIT(10), 0); 35 static SUNXI_CCU_GATE(iep_drc0_clk, "iep-drc0", "de", 36 0x00, BIT(12), 0); 37 static SUNXI_CCU_GATE(iep_drc1_clk, "iep-drc1", "de", 38 0x00, BIT(13), 0); 39 static SUNXI_CCU_GATE(merge_clk, "merge", "de", 40 0x00, BIT(20), 0); 41 42 static SUNXI_CCU_GATE(dram_fe0_clk, "dram-fe0", "sdram", 43 0x04, BIT(0), 0); 44 static SUNXI_CCU_GATE(dram_fe1_clk, "dram-fe1", "sdram", 45 0x04, BIT(1), 0); 46 static SUNXI_CCU_GATE(dram_fe2_clk, "dram-fe2", "sdram", 47 0x04, BIT(2), 0); 48 static SUNXI_CCU_GATE(dram_deu0_clk, "dram-deu0", "sdram", 49 0x04, BIT(4), 0); 50 static SUNXI_CCU_GATE(dram_deu1_clk, "dram-deu1", "sdram", 51 0x04, BIT(5), 0); 52 static SUNXI_CCU_GATE(dram_be0_clk, "dram-be0", "sdram", 53 0x04, BIT(8), 0); 54 static SUNXI_CCU_GATE(dram_be1_clk, "dram-be1", "sdram", 55 0x04, BIT(9), 0); 56 static SUNXI_CCU_GATE(dram_be2_clk, "dram-be2", "sdram", 57 0x04, BIT(10), 0); 58 static SUNXI_CCU_GATE(dram_drc0_clk, "dram-drc0", "sdram", 59 0x04, BIT(12), 0); 60 static SUNXI_CCU_GATE(dram_drc1_clk, "dram-drc1", "sdram", 61 0x04, BIT(13), 0); 62 63 static SUNXI_CCU_GATE(bus_fe0_clk, "bus-fe0", "bus-de", 64 0x08, BIT(0), 0); 65 static SUNXI_CCU_GATE(bus_fe1_clk, "bus-fe1", "bus-de", 66 0x08, BIT(1), 0); 67 static SUNXI_CCU_GATE(bus_fe2_clk, "bus-fe2", "bus-de", 68 0x08, BIT(2), 0); 69 static SUNXI_CCU_GATE(bus_deu0_clk, "bus-deu0", "bus-de", 70 0x08, BIT(4), 0); 71 static SUNXI_CCU_GATE(bus_deu1_clk, "bus-deu1", "bus-de", 72 0x08, BIT(5), 0); 73 static SUNXI_CCU_GATE(bus_be0_clk, "bus-be0", "bus-de", 74 0x08, BIT(8), 0); 75 static SUNXI_CCU_GATE(bus_be1_clk, "bus-be1", "bus-de", 76 0x08, BIT(9), 0); 77 static SUNXI_CCU_GATE(bus_be2_clk, "bus-be2", "bus-de", 78 0x08, BIT(10), 0); 79 static SUNXI_CCU_GATE(bus_drc0_clk, "bus-drc0", "bus-de", 80 0x08, BIT(12), 0); 81 static SUNXI_CCU_GATE(bus_drc1_clk, "bus-drc1", "bus-de", 82 0x08, BIT(13), 0); 83 84 static SUNXI_CCU_M(fe0_div_clk, "fe0-div", "de", 0x20, 0, 4, 0); 85 static SUNXI_CCU_M(fe1_div_clk, "fe1-div", "de", 0x20, 4, 4, 0); 86 static SUNXI_CCU_M(fe2_div_clk, "fe2-div", "de", 0x20, 8, 4, 0); 87 static SUNXI_CCU_M(be0_div_clk, "be0-div", "de", 0x20, 16, 4, 0); 88 static SUNXI_CCU_M(be1_div_clk, "be1-div", "de", 0x20, 20, 4, 0); 89 static SUNXI_CCU_M(be2_div_clk, "be2-div", "de", 0x20, 24, 4, 0); 90 91 static struct ccu_common *sun9i_a80_de_clks[] = { 92 &fe0_clk.common, 93 &fe1_clk.common, 94 &fe2_clk.common, 95 &iep_deu0_clk.common, 96 &iep_deu1_clk.common, 97 &be0_clk.common, 98 &be1_clk.common, 99 &be2_clk.common, 100 &iep_drc0_clk.common, 101 &iep_drc1_clk.common, 102 &merge_clk.common, 103 104 &dram_fe0_clk.common, 105 &dram_fe1_clk.common, 106 &dram_fe2_clk.common, 107 &dram_deu0_clk.common, 108 &dram_deu1_clk.common, 109 &dram_be0_clk.common, 110 &dram_be1_clk.common, 111 &dram_be2_clk.common, 112 &dram_drc0_clk.common, 113 &dram_drc1_clk.common, 114 115 &bus_fe0_clk.common, 116 &bus_fe1_clk.common, 117 &bus_fe2_clk.common, 118 &bus_deu0_clk.common, 119 &bus_deu1_clk.common, 120 &bus_be0_clk.common, 121 &bus_be1_clk.common, 122 &bus_be2_clk.common, 123 &bus_drc0_clk.common, 124 &bus_drc1_clk.common, 125 126 &fe0_div_clk.common, 127 &fe1_div_clk.common, 128 &fe2_div_clk.common, 129 &be0_div_clk.common, 130 &be1_div_clk.common, 131 &be2_div_clk.common, 132 }; 133 134 static struct clk_hw_onecell_data sun9i_a80_de_hw_clks = { 135 .hws = { 136 [CLK_FE0] = &fe0_clk.common.hw, 137 [CLK_FE1] = &fe1_clk.common.hw, 138 [CLK_FE2] = &fe2_clk.common.hw, 139 [CLK_IEP_DEU0] = &iep_deu0_clk.common.hw, 140 [CLK_IEP_DEU1] = &iep_deu1_clk.common.hw, 141 [CLK_BE0] = &be0_clk.common.hw, 142 [CLK_BE1] = &be1_clk.common.hw, 143 [CLK_BE2] = &be2_clk.common.hw, 144 [CLK_IEP_DRC0] = &iep_drc0_clk.common.hw, 145 [CLK_IEP_DRC1] = &iep_drc1_clk.common.hw, 146 [CLK_MERGE] = &merge_clk.common.hw, 147 148 [CLK_DRAM_FE0] = &dram_fe0_clk.common.hw, 149 [CLK_DRAM_FE1] = &dram_fe1_clk.common.hw, 150 [CLK_DRAM_FE2] = &dram_fe2_clk.common.hw, 151 [CLK_DRAM_DEU0] = &dram_deu0_clk.common.hw, 152 [CLK_DRAM_DEU1] = &dram_deu1_clk.common.hw, 153 [CLK_DRAM_BE0] = &dram_be0_clk.common.hw, 154 [CLK_DRAM_BE1] = &dram_be1_clk.common.hw, 155 [CLK_DRAM_BE2] = &dram_be2_clk.common.hw, 156 [CLK_DRAM_DRC0] = &dram_drc0_clk.common.hw, 157 [CLK_DRAM_DRC1] = &dram_drc1_clk.common.hw, 158 159 [CLK_BUS_FE0] = &bus_fe0_clk.common.hw, 160 [CLK_BUS_FE1] = &bus_fe1_clk.common.hw, 161 [CLK_BUS_FE2] = &bus_fe2_clk.common.hw, 162 [CLK_BUS_DEU0] = &bus_deu0_clk.common.hw, 163 [CLK_BUS_DEU1] = &bus_deu1_clk.common.hw, 164 [CLK_BUS_BE0] = &bus_be0_clk.common.hw, 165 [CLK_BUS_BE1] = &bus_be1_clk.common.hw, 166 [CLK_BUS_BE2] = &bus_be2_clk.common.hw, 167 [CLK_BUS_DRC0] = &bus_drc0_clk.common.hw, 168 [CLK_BUS_DRC1] = &bus_drc1_clk.common.hw, 169 170 [CLK_FE0_DIV] = &fe0_div_clk.common.hw, 171 [CLK_FE1_DIV] = &fe1_div_clk.common.hw, 172 [CLK_FE2_DIV] = &fe2_div_clk.common.hw, 173 [CLK_BE0_DIV] = &be0_div_clk.common.hw, 174 [CLK_BE1_DIV] = &be1_div_clk.common.hw, 175 [CLK_BE2_DIV] = &be2_div_clk.common.hw, 176 }, 177 .num = CLK_NUMBER, 178 }; 179 180 static const struct ccu_reset_map sun9i_a80_de_resets[] = { 181 [RST_FE0] = { 0x0c, BIT(0) }, 182 [RST_FE1] = { 0x0c, BIT(1) }, 183 [RST_FE2] = { 0x0c, BIT(2) }, 184 [RST_DEU0] = { 0x0c, BIT(4) }, 185 [RST_DEU1] = { 0x0c, BIT(5) }, 186 [RST_BE0] = { 0x0c, BIT(8) }, 187 [RST_BE1] = { 0x0c, BIT(9) }, 188 [RST_BE2] = { 0x0c, BIT(10) }, 189 [RST_DRC0] = { 0x0c, BIT(12) }, 190 [RST_DRC1] = { 0x0c, BIT(13) }, 191 [RST_MERGE] = { 0x0c, BIT(20) }, 192 }; 193 194 static const struct sunxi_ccu_desc sun9i_a80_de_clk_desc = { 195 .ccu_clks = sun9i_a80_de_clks, 196 .num_ccu_clks = ARRAY_SIZE(sun9i_a80_de_clks), 197 198 .hw_clks = &sun9i_a80_de_hw_clks, 199 200 .resets = sun9i_a80_de_resets, 201 .num_resets = ARRAY_SIZE(sun9i_a80_de_resets), 202 }; 203 204 static int sun9i_a80_de_clk_probe(struct platform_device *pdev) 205 { 206 struct clk *bus_clk; 207 struct reset_control *rstc; 208 void __iomem *reg; 209 int ret; 210 211 reg = devm_platform_ioremap_resource(pdev, 0); 212 if (IS_ERR(reg)) 213 return PTR_ERR(reg); 214 215 bus_clk = devm_clk_get(&pdev->dev, "bus"); 216 if (IS_ERR(bus_clk)) 217 return dev_err_probe(&pdev->dev, PTR_ERR(bus_clk), 218 "Couldn't get bus clk\n"); 219 220 rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); 221 if (IS_ERR(rstc)) 222 return dev_err_probe(&pdev->dev, PTR_ERR(rstc), 223 "Couldn't get reset control\n"); 224 225 /* The bus clock needs to be enabled for us to access the registers */ 226 ret = clk_prepare_enable(bus_clk); 227 if (ret) { 228 dev_err(&pdev->dev, "Couldn't enable bus clk: %d\n", ret); 229 return ret; 230 } 231 232 /* The reset control needs to be asserted for the controls to work */ 233 ret = reset_control_deassert(rstc); 234 if (ret) { 235 dev_err(&pdev->dev, 236 "Couldn't deassert reset control: %d\n", ret); 237 goto err_disable_clk; 238 } 239 240 ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun9i_a80_de_clk_desc); 241 if (ret) 242 goto err_assert_reset; 243 244 return 0; 245 246 err_assert_reset: 247 reset_control_assert(rstc); 248 err_disable_clk: 249 clk_disable_unprepare(bus_clk); 250 return ret; 251 } 252 253 static const struct of_device_id sun9i_a80_de_clk_ids[] = { 254 { .compatible = "allwinner,sun9i-a80-de-clks" }, 255 { } 256 }; 257 MODULE_DEVICE_TABLE(of, sun9i_a80_de_clk_ids); 258 259 static struct platform_driver sun9i_a80_de_clk_driver = { 260 .probe = sun9i_a80_de_clk_probe, 261 .driver = { 262 .name = "sun9i-a80-de-clks", 263 .suppress_bind_attrs = true, 264 .of_match_table = sun9i_a80_de_clk_ids, 265 }, 266 }; 267 module_platform_driver(sun9i_a80_de_clk_driver); 268 269 MODULE_IMPORT_NS(SUNXI_CCU); 270 MODULE_DESCRIPTION("Support for the Allwinner A80 Display Engine CCU"); 271 MODULE_LICENSE("GPL"); 272