1 /* $NetBSD: sun4i_a10_ccu.c,v 1.11 2019/08/01 22:23:16 tnn Exp $ */ 2 3 /*- 4 * Copyright (c) 2017 Jared McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 31 __KERNEL_RCSID(1, "$NetBSD: sun4i_a10_ccu.c,v 1.11 2019/08/01 22:23:16 tnn Exp $"); 32 33 #include <sys/param.h> 34 #include <sys/bus.h> 35 #include <sys/device.h> 36 #include <sys/systm.h> 37 38 #include <dev/fdt/fdtvar.h> 39 40 #include <arm/sunxi/sunxi_ccu.h> 41 #include <arm/sunxi/sun4i_a10_ccu.h> 42 #include <arm/sunxi/sun7i_a20_ccu.h> 43 44 #define PLL1_CFG_REG 0x000 45 #define PLL2_CFG_REG 0x008 46 #define PLL3_CFG_REG 0x010 47 #define PLL5_CFG_REG 0x020 48 #define PLL6_CFG_REG 0x028 49 #define PLL7_CFG_REG 0x030 50 #define OSC24M_CFG_REG 0x050 51 #define CPU_AHB_APB0_CFG_REG 0x054 52 #define APB1_CLK_DIV_REG 0x058 53 #define AHB_GATING_REG0 0x060 54 #define AHB_GATING_REG1 0x064 55 #define APB0_GATING_REG 0x068 56 #define APB1_GATING_REG 0x06c 57 #define NAND_SCLK_CFG_REG 0x080 58 #define SD0_SCLK_CFG_REG 0x088 59 #define SD1_SCLK_CFG_REG 0x08c 60 #define SD2_SCLK_CFG_REG 0x090 61 #define SD3_SCLK_CFG_REG 0x094 62 #define SPI0_CLK_CFG_REG 0x0a0 63 #define SPI1_CLK_CFG_REG 0x0a4 64 #define SPI2_CLK_CFG_REG 0x0a8 65 #define SATA_CFG_REG 0x0c8 66 #define USBPHY_CFG_REG 0x0cc 67 #define SPI3_CLK_CFG_REG 0x0d4 68 #define DRAM_GATING_REG 0x100 69 #define BE0_CFG_REG 0x104 70 #define BE1_CFG_REG 0x108 71 #define FE0_CFG_REG 0x10c 72 #define FE1_CFG_REG 0x110 73 #define MP_CFG_REG 0x114 74 #define LCD0CH0_CFG_REG 0x118 75 #define LCD1CH0_CFG_REG 0x11c 76 #define LCD0CH1_CFG_REG 0x12c 77 #define LCD1CH1_CFG_REG 0x130 78 #define CSI_CFG_REG 0x134 79 #define VE_CFG_REG 0x13c 80 #define AUDIO_CODEC_SCLK_CFG_REG 0x140 81 #define LVDS_CFG_REG 0x14c 82 #define HDMI_CLOCK_CFG_REG 0x150 83 #define MALI_CLOCK_CFG_REG 0x154 84 #define IEP_SCLK_CFG_REG 0x160 85 86 static int sun4i_a10_ccu_match(device_t, cfdata_t, void *); 87 static void sun4i_a10_ccu_attach(device_t, device_t, void *); 88 89 enum sun4i_a10_ccu_type { 90 CCU_A10 = 1, 91 CCU_A20, 92 }; 93 94 static const struct of_compat_data compat_data[] = { 95 { "allwinner,sun4i-a10-ccu", CCU_A10 }, 96 { "allwinner,sun7i-a20-ccu", CCU_A20 }, 97 { NULL } 98 }; 99 100 CFATTACH_DECL_NEW(sunxi_a10_ccu, sizeof(struct sunxi_ccu_softc), 101 sun4i_a10_ccu_match, sun4i_a10_ccu_attach, NULL, NULL); 102 103 static struct sunxi_ccu_reset sun4i_a10_ccu_resets[] = { 104 SUNXI_CCU_RESET(A10_RST_USB_PHY0, USBPHY_CFG_REG, 0), 105 SUNXI_CCU_RESET(A10_RST_USB_PHY1, USBPHY_CFG_REG, 1), 106 SUNXI_CCU_RESET(A10_RST_USB_PHY2, USBPHY_CFG_REG, 2), 107 SUNXI_CCU_RESET(A10_RST_DE_BE0, BE0_CFG_REG, 30), 108 SUNXI_CCU_RESET(A10_RST_DE_BE1, BE1_CFG_REG, 30), 109 SUNXI_CCU_RESET(A10_RST_DE_FE0, FE0_CFG_REG, 30), 110 SUNXI_CCU_RESET(A10_RST_DE_FE1, FE1_CFG_REG, 30), 111 SUNXI_CCU_RESET(A10_RST_DE_MP, MP_CFG_REG, 30), 112 SUNXI_CCU_RESET(A10_RST_TCON0, LCD0CH0_CFG_REG, 30), 113 SUNXI_CCU_RESET(A10_RST_TCON1, LCD1CH0_CFG_REG, 30), 114 SUNXI_CCU_RESET(A10_RST_LVDS, LVDS_CFG_REG, 0), 115 }; 116 117 static const char *cpu_parents[] = { "losc", "osc24m", "pll_core", "pll_periph" }; 118 static const char *axi_parents[] = { "cpu" }; 119 static const char *ahb_parents[] = { "axi", "pll_periph", "pll_periph_base" }; 120 static const char *apb0_parents[] = { "ahb" }; 121 static const char *apb1_parents[] = { "osc24m", "pll_periph", "losc" }; 122 static const char *mod_parents[] = { "osc24m", "pll_periph", "pll_ddr_other" }; 123 static const char *sata_parents[] = { "pll6_periph_sata", "external" }; 124 static const char *de_parents[] = { "pll_video0", "pll_video1", "pll_ddr_other" }; 125 static const char *lcd_parents[] = { "pll_video0", "pll_video1", "pll_video0x2", "pll_video1x2" }; 126 127 static const struct sunxi_ccu_nkmp_tbl sun4i_a10_pll1_table[] = { 128 { 1008000000, 21, 1, 0, 0 }, 129 { 960000000, 20, 1, 0, 0 }, 130 { 912000000, 19, 1, 0, 0 }, 131 { 864000000, 18, 1, 0, 0 }, 132 { 720000000, 30, 0, 0, 0 }, 133 { 624000000, 26, 0, 0, 0 }, 134 { 528000000, 22, 0, 0, 0 }, 135 { 312000000, 13, 0, 0, 0 }, 136 { 144000000, 12, 0, 0, 1 }, 137 { 0 } 138 }; 139 140 static const struct sunxi_ccu_nkmp_tbl sun4i_a10_ac_dig_table[] = { 141 { 24576000, 86, 0, 21, 4 }, 142 { 0 } 143 }; 144 145 /* 146 * some special cases 147 * hardcode lcd0 (tcon0) to pll3 and lcd1 (tcon1) to pll7. 148 * compute pll rate based on desired pixel clock 149 */ 150 151 static int sun4i_a10_ccu_lcd0ch0_set_rate(struct sunxi_ccu_softc *, 152 struct sunxi_ccu_clk *, u_int); 153 static int sun4i_a10_ccu_lcd1ch0_set_rate(struct sunxi_ccu_softc *, 154 struct sunxi_ccu_clk *, u_int); 155 static u_int sun4i_a10_ccu_lcd0ch0_round_rate(struct sunxi_ccu_softc *, 156 struct sunxi_ccu_clk *, u_int); 157 static u_int sun4i_a10_ccu_lcd1ch0_round_rate(struct sunxi_ccu_softc *, 158 struct sunxi_ccu_clk *, u_int); 159 static int sun4i_a10_ccu_lcd0ch1_set_rate(struct sunxi_ccu_softc *, 160 struct sunxi_ccu_clk *, u_int); 161 static int sun4i_a10_ccu_lcd1ch1_set_rate(struct sunxi_ccu_softc *, 162 struct sunxi_ccu_clk *, u_int); 163 164 static struct sunxi_ccu_clk sun4i_a10_ccu_clks[] = { 165 SUNXI_CCU_GATE(A10_CLK_HOSC, "osc24m", "hosc", 166 OSC24M_CFG_REG, 0), 167 168 SUNXI_CCU_NKMP_TABLE(A10_CLK_PLL_CORE, "pll_core", "osc24m", 169 PLL1_CFG_REG, /* reg */ 170 __BITS(12,8), /* n */ 171 __BITS(5,4), /* k */ 172 __BITS(1,0), /* m */ 173 __BITS(17,16), /* p */ 174 __BIT(31), /* enable */ 175 0, /* lock */ 176 sun4i_a10_pll1_table, /* table */ 177 SUNXI_CCU_NKMP_FACTOR_P_POW2 | SUNXI_CCU_NKMP_FACTOR_N_EXACT | 178 SUNXI_CCU_NKMP_FACTOR_N_ZERO_IS_ONE | SUNXI_CCU_NKMP_SCALE_CLOCK), 179 180 SUNXI_CCU_NKMP_TABLE(A10_CLK_PLL_AUDIO_BASE, "pll_audio", "osc24m", 181 PLL2_CFG_REG, /* reg */ 182 __BITS(14,8), /* n */ 183 0, /* k */ 184 __BITS(4,0), /* m */ 185 __BITS(29,26), /* p */ 186 __BIT(31), /* enable */ 187 0, /* lock */ 188 sun4i_a10_ac_dig_table, /* table */ 189 0), 190 191 SUNXI_CCU_NKMP(A10_CLK_PLL_PERIPH_BASE, "pll_periph_base", "osc24m", 192 PLL6_CFG_REG, /* reg */ 193 __BITS(12,8), /* n */ 194 __BITS(5,4), /* k */ 195 0, /* m */ 196 0, /* p */ 197 __BIT(31), /* enable */ 198 SUNXI_CCU_NKMP_FACTOR_N_EXACT), 199 200 SUNXI_CCU_FIXED_FACTOR(A10_CLK_PLL_PERIPH, "pll_periph", "pll_periph_base", 201 2, 1), 202 203 SUNXI_CCU_NKMP(A10_CLK_PLL_PERIPH_SATA, "pll_periph_sata", "pll_periph_base", 204 PLL6_CFG_REG, /* reg */ 205 0, /* n */ 206 0, /* k */ 207 __BITS(1,0), /* m */ 208 0, /* p */ 209 __BIT(14), /* enable */ 210 0), 211 212 SUNXI_CCU_DIV_GATE(A10_CLK_SATA, "sata", sata_parents, 213 SATA_CFG_REG, /* reg */ 214 0, /* div */ 215 __BIT(24), /* sel */ 216 __BIT(31), /* enable */ 217 0), 218 219 SUNXI_CCU_NKMP(A10_CLK_PLL_DDR_BASE, "pll_ddr_other", "osc24m", 220 PLL5_CFG_REG, /* reg */ 221 __BITS(12, 8), /* n */ 222 __BITS(5,4), /* k */ 223 0, /* m */ 224 __BITS(17,16), /* p */ 225 __BIT(31), /* enable */ 226 SUNXI_CCU_NKMP_FACTOR_N_EXACT | SUNXI_CCU_NKMP_FACTOR_P_POW2), 227 228 SUNXI_CCU_NKMP(A10_CLK_PLL_DDR, "pll_ddr", "osc24m", 229 PLL5_CFG_REG, /* reg */ 230 __BITS(12, 8), /* n */ 231 __BITS(5,4), /* k */ 232 __BITS(1,0), /* m */ 233 0, /* p */ 234 __BIT(31), /* enable */ 235 SUNXI_CCU_NKMP_FACTOR_N_EXACT), 236 237 SUNXI_CCU_DIV(A10_CLK_CPU, "cpu", cpu_parents, 238 CPU_AHB_APB0_CFG_REG, /* reg */ 239 0, /* div */ 240 __BITS(17,16), /* sel */ 241 SUNXI_CCU_DIV_SET_RATE_PARENT), 242 243 SUNXI_CCU_DIV(A10_CLK_AXI, "axi", axi_parents, 244 CPU_AHB_APB0_CFG_REG, /* reg */ 245 __BITS(1,0), /* div */ 246 0, /* sel */ 247 0), 248 249 SUNXI_CCU_DIV(A10_CLK_AHB, "ahb", ahb_parents, 250 CPU_AHB_APB0_CFG_REG, /* reg */ 251 __BITS(5,4), /* div */ 252 __BITS(7,6), /* sel */ 253 SUNXI_CCU_DIV_POWER_OF_TWO), 254 255 SUNXI_CCU_DIV(A10_CLK_APB0, "apb0", apb0_parents, 256 CPU_AHB_APB0_CFG_REG, /* reg */ 257 __BITS(9,8), /* div */ 258 0, /* sel */ 259 SUNXI_CCU_DIV_ZERO_IS_ONE | SUNXI_CCU_DIV_POWER_OF_TWO), 260 261 SUNXI_CCU_NM(A10_CLK_APB1, "apb1", apb1_parents, 262 APB1_CLK_DIV_REG, /* reg */ 263 __BITS(17,16), /* n */ 264 __BITS(4,0), /* m */ 265 __BITS(25,24), /* sel */ 266 0, /* enable */ 267 SUNXI_CCU_NM_POWER_OF_TWO), 268 269 SUNXI_CCU_NM(A10_CLK_NAND, "nand", mod_parents, 270 NAND_SCLK_CFG_REG, /* reg */ 271 __BITS(17,16), /* n */ 272 __BITS(3,0), /* m */ 273 __BITS(25,24), /* sel */ 274 __BIT(31), /* enable */ 275 SUNXI_CCU_NM_POWER_OF_TWO), 276 277 SUNXI_CCU_NM(A10_CLK_SPI0, "spi0", mod_parents, 278 SPI0_CLK_CFG_REG, /* reg */ 279 __BITS(17,16), /* n */ 280 __BITS(3,0), /* m */ 281 __BITS(25,24), /* sel */ 282 __BIT(31), /* enable */ 283 SUNXI_CCU_NM_POWER_OF_TWO), 284 285 SUNXI_CCU_NM(A10_CLK_SPI1, "spi1", mod_parents, 286 SPI1_CLK_CFG_REG, /* reg */ 287 __BITS(17,16), /* n */ 288 __BITS(3,0), /* m */ 289 __BITS(25,24), /* sel */ 290 __BIT(31), /* enable */ 291 SUNXI_CCU_NM_POWER_OF_TWO), 292 293 SUNXI_CCU_NM(A10_CLK_SPI2, "spi2", mod_parents, 294 SPI2_CLK_CFG_REG, /* reg */ 295 __BITS(17,16), /* n */ 296 __BITS(3,0), /* m */ 297 __BITS(25,24), /* sel */ 298 __BIT(31), /* enable */ 299 SUNXI_CCU_NM_POWER_OF_TWO), 300 301 SUNXI_CCU_NM(A10_CLK_SPI3, "spi3", mod_parents, 302 SPI3_CLK_CFG_REG, /* reg */ 303 __BITS(17,16), /* n */ 304 __BITS(3,0), /* m */ 305 __BITS(25,24), /* sel */ 306 __BIT(31), /* enable */ 307 SUNXI_CCU_NM_POWER_OF_TWO), 308 309 SUNXI_CCU_NM(A10_CLK_MMC0, "mmc0", mod_parents, 310 SD0_SCLK_CFG_REG, /* reg */ 311 __BITS(17,16), /* n */ 312 __BITS(3,0), /* m */ 313 __BITS(25,24), /* sel */ 314 __BIT(31), /* enable */ 315 SUNXI_CCU_NM_POWER_OF_TWO), 316 SUNXI_CCU_PHASE(A10_CLK_MMC0_SAMPLE, "mmc0_sample", "mmc0", 317 SD0_SCLK_CFG_REG, __BITS(22,20)), 318 SUNXI_CCU_PHASE(A10_CLK_MMC0_OUTPUT, "mmc0_output", "mmc0", 319 SD0_SCLK_CFG_REG, __BITS(10,8)), 320 SUNXI_CCU_NM(A10_CLK_MMC1, "mmc1", mod_parents, 321 SD1_SCLK_CFG_REG, /* reg */ 322 __BITS(17,16), /* n */ 323 __BITS(3,0), /* m */ 324 __BITS(25,24), /* sel */ 325 __BIT(31), /* enable */ 326 SUNXI_CCU_NM_POWER_OF_TWO), 327 SUNXI_CCU_PHASE(A10_CLK_MMC1_SAMPLE, "mmc1_sample", "mmc1", 328 SD1_SCLK_CFG_REG, __BITS(22,20)), 329 SUNXI_CCU_PHASE(A10_CLK_MMC1_OUTPUT, "mmc1_output", "mmc1", 330 SD1_SCLK_CFG_REG, __BITS(10,8)), 331 SUNXI_CCU_NM(A10_CLK_MMC2, "mmc2", mod_parents, 332 SD2_SCLK_CFG_REG, /* reg */ 333 __BITS(17,16), /* n */ 334 __BITS(3,0), /* m */ 335 __BITS(25,24), /* sel */ 336 __BIT(31), /* enable */ 337 SUNXI_CCU_NM_POWER_OF_TWO), 338 SUNXI_CCU_PHASE(A10_CLK_MMC2_SAMPLE, "mmc2_sample", "mmc2", 339 SD2_SCLK_CFG_REG, __BITS(22,20)), 340 SUNXI_CCU_PHASE(A10_CLK_MMC2_OUTPUT, "mmc2_output", "mmc2", 341 SD2_SCLK_CFG_REG, __BITS(10,8)), 342 SUNXI_CCU_NM(A10_CLK_MMC3, "mmc3", mod_parents, 343 SD3_SCLK_CFG_REG, /* reg */ 344 __BITS(17,16), /* n */ 345 __BITS(3,0), /* m */ 346 __BITS(25,24), /* sel */ 347 __BIT(31), /* enable */ 348 SUNXI_CCU_NM_POWER_OF_TWO), 349 SUNXI_CCU_PHASE(A10_CLK_MMC3_SAMPLE, "mmc3_sample", "mmc3", 350 SD3_SCLK_CFG_REG, __BITS(22,20)), 351 SUNXI_CCU_PHASE(A10_CLK_MMC3_OUTPUT, "mmc3_output", "mmc3", 352 SD3_SCLK_CFG_REG, __BITS(10,8)), 353 354 SUNXI_CCU_FRACTIONAL(A10_CLK_PLL_VIDEO0, "pll_video0", "osc24m", 355 PLL3_CFG_REG, /* reg */ 356 __BITS(7,0), /* m */ 357 9, /* m_min */ 358 127, /* m_max */ 359 __BIT(15), /* div_en */ 360 __BIT(14), /* frac_sel */ 361 270000000, 297000000, /* frac values */ 362 0, /* prediv */ 363 8, /* prediv_val */ 364 __BIT(31), /* enable */ 365 0), 366 SUNXI_CCU_FRACTIONAL(A10_CLK_PLL_VIDEO1, "pll_video1", "osc24m", 367 PLL7_CFG_REG, /* reg */ 368 __BITS(7,0), /* m */ 369 9, /* m_min */ 370 127, /* m_max */ 371 __BIT(15), /* div_en */ 372 __BIT(14), /* frac_sel */ 373 270000000, 297000000, /* frac values */ 374 0, /* prediv */ 375 8, /* prediv_val */ 376 __BIT(31), /* enable */ 377 0), 378 SUNXI_CCU_FIXED_FACTOR(A10_CLK_PLL_VIDEO0_2X, 379 "pll_video0x2", "pll_video0", 380 1, 2), 381 SUNXI_CCU_FIXED_FACTOR(A10_CLK_PLL_VIDEO1_2X, 382 "pll_video1x2", "pll_video1", 383 1, 2), 384 385 SUNXI_CCU_DIV_GATE(A10_CLK_DE_BE0, "debe0-mod", de_parents, 386 BE0_CFG_REG, /* reg */ 387 __BITS(3,0), /* div */ 388 __BITS(25,24), /* sel */ 389 __BIT(31), /* enable */ 390 0 /* flags */ 391 ), 392 SUNXI_CCU_DIV_GATE(A10_CLK_DE_BE1, "debe1-mod", de_parents, 393 BE1_CFG_REG, /* reg */ 394 __BITS(3,0), /* div */ 395 __BITS(25,24), /* sel */ 396 __BIT(31), /* enable */ 397 0 /* flags */ 398 ), 399 SUNXI_CCU_DIV_GATE(A10_CLK_DE_FE0, "defe0-mod", de_parents, 400 FE0_CFG_REG, /* reg */ 401 __BITS(3,0), /* div */ 402 __BITS(25,24), /* sel */ 403 __BIT(31), /* enable */ 404 0 /* flags */ 405 ), 406 SUNXI_CCU_DIV_GATE(A10_CLK_DE_FE1, "defe1-mod", de_parents, 407 FE1_CFG_REG, /* reg */ 408 __BITS(3,0), /* div */ 409 __BITS(25,24), /* sel */ 410 __BIT(31), /* enable */ 411 0 /* flags */ 412 ), 413 [A10_CLK_TCON0_CH0] = { 414 .type = SUNXI_CCU_DIV, 415 .base.name = "tcon0-ch0", 416 .u.div.reg = LCD0CH0_CFG_REG, 417 .u.div.parents = lcd_parents, 418 .u.div.nparents = __arraycount(lcd_parents), 419 .u.div.div = 0, 420 .u.div.sel = __BITS(25,24), 421 .u.div.enable = __BIT(31), 422 .u.div.flags = 0, 423 .enable = sunxi_ccu_div_enable, 424 .get_rate = sunxi_ccu_div_get_rate, 425 .set_rate = sun4i_a10_ccu_lcd0ch0_set_rate, 426 .round_rate = sun4i_a10_ccu_lcd0ch0_round_rate, 427 .set_parent = sunxi_ccu_div_set_parent, 428 .get_parent = sunxi_ccu_div_get_parent, 429 }, 430 [A10_CLK_TCON1_CH0] = { 431 .type = SUNXI_CCU_DIV, 432 .base.name = "tcon1-ch0", 433 .u.div.reg = LCD1CH0_CFG_REG, 434 .u.div.parents = lcd_parents, 435 .u.div.nparents = __arraycount(lcd_parents), 436 .u.div.div = 0, 437 .u.div.sel = __BITS(25,24), 438 .u.div.enable = __BIT(31), 439 .u.div.flags = 0, 440 .enable = sunxi_ccu_div_enable, 441 .get_rate = sunxi_ccu_div_get_rate, 442 .set_rate = sun4i_a10_ccu_lcd1ch0_set_rate, 443 .round_rate = sun4i_a10_ccu_lcd1ch0_round_rate, 444 .set_parent = sunxi_ccu_div_set_parent, 445 .get_parent = sunxi_ccu_div_get_parent, 446 }, 447 [A10_CLK_TCON0_CH1] = { 448 .type = SUNXI_CCU_DIV, 449 .base.name = "tcon0-ch1", 450 .u.div.reg = LCD0CH1_CFG_REG, 451 .u.div.parents = lcd_parents, 452 .u.div.nparents = __arraycount(lcd_parents), 453 .u.div.div = __BITS(3,0), 454 .u.div.sel = __BITS(25,24), 455 .u.div.enable = __BIT(15) | __BIT(31), 456 .u.div.flags = 0, 457 .enable = sunxi_ccu_div_enable, 458 .get_rate = sunxi_ccu_div_get_rate, 459 .set_rate = sun4i_a10_ccu_lcd0ch1_set_rate, 460 .set_parent = sunxi_ccu_div_set_parent, 461 .get_parent = sunxi_ccu_div_get_parent, 462 }, 463 [A10_CLK_TCON1_CH1] = { 464 .type = SUNXI_CCU_DIV, 465 .base.name = "tcon1-ch1", 466 .u.div.reg = LCD1CH1_CFG_REG, 467 .u.div.parents = lcd_parents, 468 .u.div.nparents = __arraycount(lcd_parents), 469 .u.div.div = __BITS(3,0), 470 .u.div.sel = __BITS(25,24), 471 .u.div.enable = __BIT(15) | __BIT(31), 472 .u.div.flags = 0, 473 .enable = sunxi_ccu_div_enable, 474 .get_rate = sunxi_ccu_div_get_rate, 475 .set_rate = sun4i_a10_ccu_lcd1ch1_set_rate, 476 .set_parent = sunxi_ccu_div_set_parent, 477 .get_parent = sunxi_ccu_div_get_parent, 478 }, 479 SUNXI_CCU_DIV_GATE(A10_CLK_HDMI, "hdmi-mod", lcd_parents, 480 HDMI_CLOCK_CFG_REG, /* reg */ 481 __BITS(3,0), /* div */ 482 __BITS(25,24), /* sel */ 483 __BIT(31), /* enable */ 484 0 /* flags */ 485 ), 486 487 /* AHB_GATING_REG0 */ 488 SUNXI_CCU_GATE(A10_CLK_AHB_OTG, "ahb-otg", "ahb", 489 AHB_GATING_REG0, 0), 490 SUNXI_CCU_GATE(A10_CLK_AHB_EHCI0, "ahb-ehci0", "ahb", 491 AHB_GATING_REG0, 1), 492 SUNXI_CCU_GATE(A10_CLK_AHB_OHCI0, "ahb-ohci0", "ahb", 493 AHB_GATING_REG0, 2), 494 SUNXI_CCU_GATE(A10_CLK_AHB_EHCI1, "ahb-ehci1", "ahb", 495 AHB_GATING_REG0, 3), 496 SUNXI_CCU_GATE(A10_CLK_AHB_OHCI1, "ahb-ohci1", "ahb", 497 AHB_GATING_REG0, 4), 498 SUNXI_CCU_GATE(A10_CLK_AHB_SS, "ahb-ss", "ahb", 499 AHB_GATING_REG0, 5), 500 SUNXI_CCU_GATE(A10_CLK_AHB_DMA, "ahb-dma", "ahb", 501 AHB_GATING_REG0, 6), 502 SUNXI_CCU_GATE(A10_CLK_AHB_BIST, "ahb-bist", "ahb", 503 AHB_GATING_REG0, 7), 504 SUNXI_CCU_GATE(A10_CLK_AHB_MMC0, "ahb-mmc0", "ahb", 505 AHB_GATING_REG0, 8), 506 SUNXI_CCU_GATE(A10_CLK_AHB_MMC1, "ahb-mmc1", "ahb", 507 AHB_GATING_REG0, 9), 508 SUNXI_CCU_GATE(A10_CLK_AHB_MMC2, "ahb-mmc2", "ahb", 509 AHB_GATING_REG0, 10), 510 SUNXI_CCU_GATE(A10_CLK_AHB_MMC3, "ahb-mmc3", "ahb", 511 AHB_GATING_REG0, 11), 512 SUNXI_CCU_GATE(A10_CLK_AHB_MS, "ahb-ms", "ahb", 513 AHB_GATING_REG0, 12), 514 SUNXI_CCU_GATE(A10_CLK_AHB_NAND, "ahb-nand", "ahb", 515 AHB_GATING_REG0, 13), 516 SUNXI_CCU_GATE(A10_CLK_AHB_SDRAM, "ahb-sdram", "ahb", 517 AHB_GATING_REG0, 14), 518 SUNXI_CCU_GATE(A10_CLK_AHB_ACE, "ahb-ace", "ahb", 519 AHB_GATING_REG0, 16), 520 SUNXI_CCU_GATE(A10_CLK_AHB_EMAC, "ahb-emac", "ahb", 521 AHB_GATING_REG0, 17), 522 SUNXI_CCU_GATE(A10_CLK_AHB_TS, "ahb-ts", "ahb", 523 AHB_GATING_REG0, 18), 524 SUNXI_CCU_GATE(A10_CLK_AHB_SPI0, "ahb-spi0", "ahb", 525 AHB_GATING_REG0, 20), 526 SUNXI_CCU_GATE(A10_CLK_AHB_SPI1, "ahb-spi1", "ahb", 527 AHB_GATING_REG0, 21), 528 SUNXI_CCU_GATE(A10_CLK_AHB_SPI2, "ahb-spi2", "ahb", 529 AHB_GATING_REG0, 22), 530 SUNXI_CCU_GATE(A10_CLK_AHB_SPI3, "ahb-spi3", "ahb", 531 AHB_GATING_REG0, 23), 532 SUNXI_CCU_GATE(A10_CLK_AHB_SATA, "ahb-sata", "ahb", 533 AHB_GATING_REG0, 25), 534 SUNXI_CCU_GATE(A10_CLK_AHB_HSTIMER, "ahb-hstimer", "ahb", 535 AHB_GATING_REG0, 28), 536 537 /* AHB_GATING_REG1. Missing: TVE, HDMI */ 538 SUNXI_CCU_GATE(A10_CLK_AHB_VE, "ahb-ve", "ahb", 539 AHB_GATING_REG1, 0), 540 SUNXI_CCU_GATE(A10_CLK_AHB_TVD, "ahb-tvd", "ahb", 541 AHB_GATING_REG1, 1), 542 SUNXI_CCU_GATE(A10_CLK_AHB_TVE0, "ahb-tve0", "ahb", 543 AHB_GATING_REG1, 2), 544 SUNXI_CCU_GATE(A10_CLK_AHB_TVE1, "ahb-tve1", "ahb", 545 AHB_GATING_REG1, 3), 546 SUNXI_CCU_GATE(A10_CLK_AHB_LCD0, "ahb-lcd0", "ahb", 547 AHB_GATING_REG1, 4), 548 SUNXI_CCU_GATE(A10_CLK_AHB_LCD1, "ahb-lcd1", "ahb", 549 AHB_GATING_REG1, 5), 550 SUNXI_CCU_GATE(A10_CLK_AHB_CSI0, "ahb-csi0", "ahb", 551 AHB_GATING_REG1, 8), 552 SUNXI_CCU_GATE(A10_CLK_AHB_CSI1, "ahb-csi1", "ahb", 553 AHB_GATING_REG1, 9), 554 SUNXI_CCU_GATE(A10_CLK_AHB_HDMI1, "ahb-hdmi1", "ahb", 555 AHB_GATING_REG1, 10), 556 SUNXI_CCU_GATE(A10_CLK_AHB_HDMI0, "ahb-hdmi0", "ahb", 557 AHB_GATING_REG1, 11), 558 SUNXI_CCU_GATE(A10_CLK_AHB_DE_BE0, "ahb-de_be0", "ahb", 559 AHB_GATING_REG1, 12), 560 SUNXI_CCU_GATE(A10_CLK_AHB_DE_BE1, "ahb-de_be1", "ahb", 561 AHB_GATING_REG1, 13), 562 SUNXI_CCU_GATE(A10_CLK_AHB_DE_FE0, "ahb-de_fe0", "ahb", 563 AHB_GATING_REG1, 14), 564 SUNXI_CCU_GATE(A10_CLK_AHB_DE_FE1, "ahb-de_fe1", "ahb", 565 AHB_GATING_REG1, 15), 566 SUNXI_CCU_GATE(A10_CLK_AHB_GMAC, "ahb-gmac", "ahb", 567 AHB_GATING_REG1, 17), 568 SUNXI_CCU_GATE(A10_CLK_AHB_MP, "ahb-mp", "ahb", 569 AHB_GATING_REG1, 18), 570 SUNXI_CCU_GATE(A10_CLK_AHB_GPU, "ahb-gpu", "ahb", 571 AHB_GATING_REG1, 20), 572 573 /* APB0_GATING_REG */ 574 SUNXI_CCU_GATE(A10_CLK_APB0_CODEC, "apb0-codec", "apb0", 575 APB0_GATING_REG, 0), 576 SUNXI_CCU_GATE(A10_CLK_APB0_SPDIF, "apb0-spdif", "apb0", 577 APB0_GATING_REG, 1), 578 SUNXI_CCU_GATE(A10_CLK_APB0_AC97, "apb0-ac97", "apb0", 579 APB0_GATING_REG, 2), 580 SUNXI_CCU_GATE(A10_CLK_APB0_I2S0, "apb0-i2s0", "apb0", 581 APB0_GATING_REG, 3), 582 SUNXI_CCU_GATE(A10_CLK_APB0_I2S1, "apb0-i2s1", "apb0", 583 APB0_GATING_REG, 4), 584 SUNXI_CCU_GATE(A10_CLK_APB0_PIO, "apb0-pio", "apb0", 585 APB0_GATING_REG, 5), 586 SUNXI_CCU_GATE(A10_CLK_APB0_IR0, "apb0-ir0", "apb0", 587 APB0_GATING_REG, 6), 588 SUNXI_CCU_GATE(A10_CLK_APB0_IR1, "apb0-ir1", "apb0", 589 APB0_GATING_REG, 7), 590 SUNXI_CCU_GATE(A10_CLK_APB0_I2S2, "apb0-i2s2", "apb0", 591 APB0_GATING_REG, 8), 592 SUNXI_CCU_GATE(A10_CLK_APB0_KEYPAD, "apb0-keypad", "apb0", 593 APB0_GATING_REG, 10), 594 595 /* APB1_GATING_REG */ 596 SUNXI_CCU_GATE(A10_CLK_APB1_I2C0, "apb1-i2c0", "apb1", 597 APB1_GATING_REG, 0), 598 SUNXI_CCU_GATE(A10_CLK_APB1_I2C1, "apb1-i2c1", "apb1", 599 APB1_GATING_REG, 1), 600 SUNXI_CCU_GATE(A10_CLK_APB1_I2C2, "apb1-i2c2", "apb1", 601 APB1_GATING_REG, 2), 602 SUNXI_CCU_GATE(A10_CLK_APB1_I2C3, "apb1-i2c3", "apb1", 603 APB1_GATING_REG, 3), 604 SUNXI_CCU_GATE(A10_CLK_APB1_CAN, "apb1-can", "apb1", 605 APB1_GATING_REG, 4), 606 SUNXI_CCU_GATE(A10_CLK_APB1_SCR, "apb1-scr", "apb1", 607 APB1_GATING_REG, 5), 608 SUNXI_CCU_GATE(A10_CLK_APB1_PS20, "apb1-ps20", "apb1", 609 APB1_GATING_REG, 6), 610 SUNXI_CCU_GATE(A10_CLK_APB1_PS21, "apb1-ps21", "apb1", 611 APB1_GATING_REG, 7), 612 SUNXI_CCU_GATE(A10_CLK_APB1_I2C4, "apb1-i2c4", "apb1", 613 APB1_GATING_REG, 15), 614 SUNXI_CCU_GATE(A10_CLK_APB1_UART0, "apb1-uart0", "apb1", 615 APB1_GATING_REG, 16), 616 SUNXI_CCU_GATE(A10_CLK_APB1_UART1, "apb1-uart1", "apb1", 617 APB1_GATING_REG, 17), 618 SUNXI_CCU_GATE(A10_CLK_APB1_UART2, "apb1-uart2", "apb1", 619 APB1_GATING_REG, 18), 620 SUNXI_CCU_GATE(A10_CLK_APB1_UART3, "apb1-uart3", "apb1", 621 APB1_GATING_REG, 19), 622 SUNXI_CCU_GATE(A10_CLK_APB1_UART4, "apb1-uart4", "apb1", 623 APB1_GATING_REG, 20), 624 SUNXI_CCU_GATE(A10_CLK_APB1_UART5, "apb1-uart5", "apb1", 625 APB1_GATING_REG, 21), 626 SUNXI_CCU_GATE(A10_CLK_APB1_UART6, "apb1-uart6", "apb1", 627 APB1_GATING_REG, 22), 628 SUNXI_CCU_GATE(A10_CLK_APB1_UART7, "apb1-uart7", "apb1", 629 APB1_GATING_REG, 23), 630 631 /* DRAM GATING */ 632 SUNXI_CCU_GATE(A10_CLK_DRAM_DE_BE0, "dram-de-be0", "pll_ddr_other", 633 DRAM_GATING_REG, 26), 634 SUNXI_CCU_GATE(A10_CLK_DRAM_DE_BE1, "dram-de-be1", "pll_ddr_other", 635 DRAM_GATING_REG, 27), 636 SUNXI_CCU_GATE(A10_CLK_DRAM_DE_FE0, "dram-de-fe0", "pll_ddr_other", 637 DRAM_GATING_REG, 25), 638 SUNXI_CCU_GATE(A10_CLK_DRAM_DE_FE1, "dram-de-fe1", "pll_ddr_other", 639 DRAM_GATING_REG, 24), 640 641 /* AUDIO_CODEC_SCLK_CFG_REG */ 642 SUNXI_CCU_GATE(A10_CLK_CODEC, "codec", "pll_audio", 643 AUDIO_CODEC_SCLK_CFG_REG, 31), 644 645 /* USBPHY_CFG_REG */ 646 SUNXI_CCU_GATE(A10_CLK_USB_OHCI0, "usb-ohci0", "osc24m", 647 USBPHY_CFG_REG, 6), 648 SUNXI_CCU_GATE(A10_CLK_USB_OHCI1, "usb-ohci1", "osc24m", 649 USBPHY_CFG_REG, 7), 650 SUNXI_CCU_GATE(A10_CLK_USB_PHY, "usb-phy", "osc24m", 651 USBPHY_CFG_REG, 8), 652 }; 653 654 /* 655 * some special cases 656 * hardcode lcd0 (tcon0) to pll3 and lcd1 (tcon1) to pll7. 657 * compute pll rate based on desired pixel clock 658 */ 659 660 static int 661 sun4i_a10_ccu_lcd0ch0_set_rate(struct sunxi_ccu_softc *sc, 662 struct sunxi_ccu_clk * clk, u_int rate) 663 { 664 int error; 665 error = sunxi_ccu_lcdxch0_set_rate(sc, clk, 666 &sun4i_a10_ccu_clks[A10_CLK_PLL_VIDEO0], 667 &sun4i_a10_ccu_clks[A10_CLK_PLL_VIDEO0_2X], 668 rate); 669 return error; 670 } 671 672 static int 673 sun4i_a10_ccu_lcd1ch0_set_rate(struct sunxi_ccu_softc *sc, 674 struct sunxi_ccu_clk * clk, u_int rate) 675 { 676 return sunxi_ccu_lcdxch0_set_rate(sc, clk, 677 &sun4i_a10_ccu_clks[A10_CLK_PLL_VIDEO1], 678 &sun4i_a10_ccu_clks[A10_CLK_PLL_VIDEO1_2X], 679 rate); 680 } 681 682 static u_int 683 sun4i_a10_ccu_lcd0ch0_round_rate(struct sunxi_ccu_softc *sc, 684 struct sunxi_ccu_clk * clk, u_int rate) 685 { 686 return sunxi_ccu_lcdxch0_round_rate(sc, clk, 687 &sun4i_a10_ccu_clks[A10_CLK_PLL_VIDEO0], 688 &sun4i_a10_ccu_clks[A10_CLK_PLL_VIDEO0_2X], 689 rate); 690 } 691 692 static u_int 693 sun4i_a10_ccu_lcd1ch0_round_rate(struct sunxi_ccu_softc *sc, 694 struct sunxi_ccu_clk * clk, u_int rate) 695 { 696 return sunxi_ccu_lcdxch0_round_rate(sc, clk, 697 &sun4i_a10_ccu_clks[A10_CLK_PLL_VIDEO1], 698 &sun4i_a10_ccu_clks[A10_CLK_PLL_VIDEO1_2X], 699 rate); 700 } 701 702 static int 703 sun4i_a10_ccu_lcd0ch1_set_rate(struct sunxi_ccu_softc *sc, 704 struct sunxi_ccu_clk * clk, u_int rate) 705 { 706 return sunxi_ccu_lcdxch1_set_rate(sc, clk, 707 &sun4i_a10_ccu_clks[A10_CLK_PLL_VIDEO0], 708 &sun4i_a10_ccu_clks[A10_CLK_PLL_VIDEO0_2X], 709 rate); 710 } 711 712 static int 713 sun4i_a10_ccu_lcd1ch1_set_rate(struct sunxi_ccu_softc *sc, 714 struct sunxi_ccu_clk * clk, u_int rate) 715 { 716 return sunxi_ccu_lcdxch1_set_rate(sc, clk, 717 &sun4i_a10_ccu_clks[A10_CLK_PLL_VIDEO1], 718 &sun4i_a10_ccu_clks[A10_CLK_PLL_VIDEO1_2X], 719 rate); 720 } 721 722 #if 0 723 static int 724 sun4i_a10_ccu_lcdxch0_set_rate(struct sunxi_ccu_softc *sc, 725 struct sunxi_ccu_clk * clk, u_int rate, int unit) 726 { 727 int parent_index; 728 struct clk *clkp; 729 int error; 730 731 parent_index = (unit == 0) ? A10_CLK_PLL_VIDEO0 : A10_CLK_PLL_VIDEO1; 732 clkp = &sun4i_a10_ccu_clks[parent_index].base; 733 error = clk_set_rate(clkp, rate); 734 if (error) { 735 error = clk_set_rate(clkp, rate / 2); 736 if (error != 0) 737 return error; 738 parent_index = 739 (unit == 0) ? A10_CLK_PLL_VIDEO0_2X : A10_CLK_PLL_VIDEO1_2X; 740 clkp = &sun4i_a10_ccu_clks[parent_index].base; 741 } 742 error = clk_set_parent(&clk->base, clkp); 743 KASSERT(error == 0); 744 return error; 745 } 746 747 static u_int 748 sun4i_a10_ccu_lcdxch0_round_rate(struct sunxi_ccu_softc *sc, 749 struct sunxi_ccu_clk * clk, u_int try_rate, int unit) 750 { 751 int parent_index; 752 struct clk *clkp; 753 int diff, diff_x2; 754 int rate, rate_x2; 755 756 parent_index = (unit == 0) ? A10_CLK_PLL_VIDEO0 : A10_CLK_PLL_VIDEO1; 757 clkp = &sun4i_a10_ccu_clks[parent_index].base; 758 rate = clk_round_rate(clkp, try_rate); 759 diff = abs(try_rate - rate); 760 761 rate_x2 = (clk_round_rate(clkp, try_rate / 2) * 2); 762 diff_x2 = abs(try_rate - rate_x2); 763 764 if (diff_x2 < diff) 765 return rate_x2; 766 return rate; 767 } 768 769 static void 770 sun4i_a10_tcon_calc_pll(int f_ref, int f_out, int *pm, int *pn, int *pd) 771 { 772 int best = INT_MAX; 773 for (int d = 1; d <= 2 && best != 0; d++) { 774 for (int m = 1; m <= 16 && best != 0; m++) { 775 for (int n = 9; n <= 127 && best != 0; n++) { 776 int f_cur = (n * f_ref * d) / m; 777 int diff = abs(f_out - f_cur); 778 if (diff < best) { 779 best = diff; 780 *pm = m; 781 *pn = n; 782 *pd = d; 783 if (diff == 0) 784 return; 785 } 786 } 787 } 788 } 789 } 790 791 static int 792 sun4i_a10_ccu_lcdxch1_set_rate(struct sunxi_ccu_softc *sc, 793 struct sunxi_ccu_clk *clk, u_int rate, int unit) 794 { 795 int parent_index; 796 struct clk *clkp, *pllclk; 797 int error; 798 int n = 0, m = 0, d = 0; 799 800 parent_index = (unit == 0) ? A10_CLK_PLL_VIDEO0 : A10_CLK_PLL_VIDEO1; 801 clkp = &sun4i_a10_ccu_clks[parent_index].base; 802 pllclk = clkp; 803 804 sun4i_a10_tcon_calc_pll(3000000, rate, &m, &n, &d); 805 806 if (n == 0 || m == 0 || d == 0) 807 return ERANGE; 808 809 if (d == 2) { 810 parent_index = 811 (unit == 0) ? A10_CLK_PLL_VIDEO0_2X : A10_CLK_PLL_VIDEO1_2X; 812 clkp = &sun4i_a10_ccu_clks[parent_index].base; 813 } 814 815 error = clk_set_rate(pllclk, 3000000 * n); 816 KASSERT(error == 0); 817 error = clk_set_parent(&clk->base, clkp); 818 KASSERT(error == 0); 819 error = sunxi_ccu_div_set_rate(sc, clk, rate); 820 KASSERT(error == 0); 821 return error; 822 } 823 #endif 824 825 static int 826 sun4i_a10_ccu_match(device_t parent, cfdata_t cf, void *aux) 827 { 828 struct fdt_attach_args * const faa = aux; 829 830 return of_match_compat_data(faa->faa_phandle, compat_data); 831 } 832 833 static struct sunxi_ccu_softc *sc0; 834 static void 835 sun4i_a10_ccu_attach(device_t parent, device_t self, void *aux) 836 { 837 struct sunxi_ccu_softc * const sc = device_private(self); 838 struct fdt_attach_args * const faa = aux; 839 enum sun4i_a10_ccu_type type; 840 struct clk *clk, *clkp; 841 int error; 842 843 sc->sc_dev = self; 844 sc->sc_phandle = faa->faa_phandle; 845 sc->sc_bst = faa->faa_bst; 846 847 sc->sc_resets = sun4i_a10_ccu_resets; 848 sc->sc_nresets = __arraycount(sun4i_a10_ccu_resets); 849 850 sc->sc_clks = sun4i_a10_ccu_clks; 851 sc->sc_nclks = __arraycount(sun4i_a10_ccu_clks); 852 853 if (sunxi_ccu_attach(sc) != 0) 854 return; 855 856 aprint_naive("\n"); 857 858 type = of_search_compatible(faa->faa_phandle, compat_data)->data; 859 860 switch (type) { 861 case CCU_A10: 862 aprint_normal(": A10 CCU\n"); 863 break; 864 case CCU_A20: 865 aprint_normal(": A20 CCU\n"); 866 break; 867 } 868 /* hardcode debe clocks parent to PLL5 */ 869 clkp = &sun4i_a10_ccu_clks[A10_CLK_PLL_DDR_BASE].base; 870 clk = &sun4i_a10_ccu_clks[A10_CLK_DE_BE0].base; 871 error = clk_set_parent(clk, clkp); 872 KASSERT(error == 0); 873 clk = &sun4i_a10_ccu_clks[A10_CLK_DE_BE1].base; 874 error = clk_set_parent(clk, clkp); 875 KASSERT(error == 0); 876 877 (void)error; 878 sunxi_ccu_print(sc); 879 sc0 = sc; 880 } 881 882 void sun4i_ccu_print(void); 883 void 884 sun4i_ccu_print(void) 885 { 886 sunxi_ccu_print(sc0); 887 } 888