1 /* $NetBSD: sun9i_a80_ccu.c,v 1.1 2017/10/08 18:00:36 jmcneill 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: sun9i_a80_ccu.c,v 1.1 2017/10/08 18:00:36 jmcneill 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/sun9i_a80_ccu.h> 42 43 /* CCU */ 44 #define PLL_PERIPH0_CTRL_REG 0x00c 45 #define PLL_PERIPH1_CTRL_REG 0x02c 46 #define GTBUS_CLK_CFG_REG 0x05c 47 #define AHB0_CLK_CFG_REG 0x060 48 #define AHB1_CLK_CFG_REG 0x064 49 #define AHB2_CLK_CFG_REG 0x068 50 #define APB0_CLK_CFG_REG 0x070 51 #define APB1_CLK_CFG_REG 0x074 52 53 /* CCU_SCLK */ 54 #define SDMMC0_CLK_REG 0x410 55 #define SDMMC1_CLK_REG 0x414 56 #define SDMMC2_CLK_REG 0x418 57 #define BUS_CLK_GATING_REG0 0x580 58 #define BUS_CLK_GATING_REG1 0x584 59 #define BUS_CLK_GATING_REG2 0x588 60 #define BUS_CLK_GATING_REG3 0x590 61 #define BUS_CLK_GATING_REG4 0x594 62 #define BUS_SOFT_RST_REG0 0x5a0 63 #define BUS_SOFT_RST_REG1 0x5a4 64 #define BUS_SOFT_RST_REG2 0x5a8 65 #define BUS_SOFT_RST_REG3 0x5b0 66 #define BUS_SOFT_RST_REG4 0x5b4 67 68 static int sun9i_a80_ccu_match(device_t, cfdata_t, void *); 69 static void sun9i_a80_ccu_attach(device_t, device_t, void *); 70 71 static const char * compatible[] = { 72 "allwinner,sun9i-a80-ccu", 73 NULL 74 }; 75 76 CFATTACH_DECL_NEW(sunxi_a80_ccu, sizeof(struct sunxi_ccu_softc), 77 sun9i_a80_ccu_match, sun9i_a80_ccu_attach, NULL, NULL); 78 79 static struct sunxi_ccu_reset sun9i_a80_ccu_resets[] = { 80 SUNXI_CCU_RESET(A80_RST_BUS_FD, BUS_SOFT_RST_REG0, 0), 81 SUNXI_CCU_RESET(A80_RST_BUS_GPU_CTRL, BUS_SOFT_RST_REG0, 3), 82 SUNXI_CCU_RESET(A80_RST_BUS_SS, BUS_SOFT_RST_REG0, 5), 83 SUNXI_CCU_RESET(A80_RST_BUS_MMC, BUS_SOFT_RST_REG0, 8), 84 SUNXI_CCU_RESET(A80_RST_BUS_NAND1, BUS_SOFT_RST_REG0, 12), 85 SUNXI_CCU_RESET(A80_RST_BUS_NAND0, BUS_SOFT_RST_REG0, 13), 86 SUNXI_CCU_RESET(A80_RST_BUS_TS, BUS_SOFT_RST_REG0, 18), 87 SUNXI_CCU_RESET(A80_RST_BUS_SPI0, BUS_SOFT_RST_REG0, 20), 88 SUNXI_CCU_RESET(A80_RST_BUS_SPI1, BUS_SOFT_RST_REG0, 21), 89 SUNXI_CCU_RESET(A80_RST_BUS_SPI2, BUS_SOFT_RST_REG0, 22), 90 SUNXI_CCU_RESET(A80_RST_BUS_SPI3, BUS_SOFT_RST_REG0, 23), 91 92 SUNXI_CCU_RESET(A80_RST_BUS_OTG_PHY, BUS_SOFT_RST_REG1, 1), 93 SUNXI_CCU_RESET(A80_RST_BUS_MSGBOX, BUS_SOFT_RST_REG1, 21), 94 SUNXI_CCU_RESET(A80_RST_BUS_SPINLOCK, BUS_SOFT_RST_REG1, 22), 95 SUNXI_CCU_RESET(A80_RST_BUS_HSTIMER, BUS_SOFT_RST_REG1, 23), 96 SUNXI_CCU_RESET(A80_RST_BUS_DMA, BUS_SOFT_RST_REG1, 24), 97 98 SUNXI_CCU_RESET(A80_RST_BUS_LCD0, BUS_SOFT_RST_REG2, 0), 99 SUNXI_CCU_RESET(A80_RST_BUS_LCD1, BUS_SOFT_RST_REG2, 1), 100 SUNXI_CCU_RESET(A80_RST_BUS_CSI, BUS_SOFT_RST_REG2, 4), 101 SUNXI_CCU_RESET(A80_RST_BUS_DE, BUS_SOFT_RST_REG2, 7), 102 SUNXI_CCU_RESET(A80_RST_BUS_MP, BUS_SOFT_RST_REG2, 8), 103 SUNXI_CCU_RESET(A80_RST_BUS_GPU, BUS_SOFT_RST_REG2, 9), 104 105 SUNXI_CCU_RESET(A80_RST_BUS_LRADC, BUS_SOFT_RST_REG3, 15), 106 SUNXI_CCU_RESET(A80_RST_BUS_GPADC, BUS_SOFT_RST_REG3, 17), 107 108 SUNXI_CCU_RESET(A80_RST_BUS_I2C0, BUS_SOFT_RST_REG4, 0), 109 SUNXI_CCU_RESET(A80_RST_BUS_I2C1, BUS_SOFT_RST_REG4, 1), 110 SUNXI_CCU_RESET(A80_RST_BUS_I2C2, BUS_SOFT_RST_REG4, 2), 111 SUNXI_CCU_RESET(A80_RST_BUS_I2C3, BUS_SOFT_RST_REG4, 3), 112 SUNXI_CCU_RESET(A80_RST_BUS_I2C4, BUS_SOFT_RST_REG4, 4), 113 SUNXI_CCU_RESET(A80_RST_BUS_UART0, BUS_SOFT_RST_REG4, 16), 114 SUNXI_CCU_RESET(A80_RST_BUS_UART1, BUS_SOFT_RST_REG4, 17), 115 SUNXI_CCU_RESET(A80_RST_BUS_UART2, BUS_SOFT_RST_REG4, 18), 116 SUNXI_CCU_RESET(A80_RST_BUS_UART3, BUS_SOFT_RST_REG4, 19), 117 SUNXI_CCU_RESET(A80_RST_BUS_UART4, BUS_SOFT_RST_REG4, 20), 118 SUNXI_CCU_RESET(A80_RST_BUS_UART5, BUS_SOFT_RST_REG4, 21), 119 }; 120 121 static const char *gtbus_parents[] = { "hosc", "pll_periph0", "pll_periph1" }; 122 static const char *ahb0_parents[] = { "gtbus", "pll_periph0", "pll_periph1" }; 123 static const char *ahb1_parents[] = { "gtbus", "pll_periph0", "pll_periph1" }; 124 static const char *ahb2_parents[] = { "hosc", "pll_periph0", "pll_periph1" }; 125 static const char *apb_parents[] = { "hosc", "pll_periph0" }; 126 static const char *mmc_parents[] = { "hosc", "pll_periph0" }; 127 128 static struct sunxi_ccu_clk sun9i_a80_ccu_clks[] = { 129 SUNXI_CCU_NKMP(A80_CLK_PLL_PERIPH0, "pll_periph0", "hosc", 130 PLL_PERIPH0_CTRL_REG, /* reg */ 131 __BITS(15,8), /* n */ 132 __BIT(16), /* k */ 133 0, /* m */ 134 __BIT(18), /* p */ 135 __BIT(31), /* enable */ 136 SUNXI_CCU_NKMP_FACTOR_N_EXACT), 137 SUNXI_CCU_NKMP(A80_CLK_PLL_PERIPH1, "pll_periph1", "hosc", 138 PLL_PERIPH1_CTRL_REG, /* reg */ 139 __BITS(15,8), /* n */ 140 __BIT(16), /* k */ 141 0, /* m */ 142 __BIT(18), /* p */ 143 __BIT(31), /* enable */ 144 SUNXI_CCU_NKMP_FACTOR_N_EXACT), 145 146 SUNXI_CCU_DIV(A80_CLK_GTBUS, "gtbus", gtbus_parents, 147 GTBUS_CLK_CFG_REG, /* reg */ 148 __BITS(1,0), /* div */ 149 __BITS(25,24), /* sel */ 150 0), 151 152 SUNXI_CCU_DIV(A80_CLK_AHB0, "ahb0", ahb0_parents, 153 AHB0_CLK_CFG_REG, /* reg */ 154 __BITS(1,0), /* div */ 155 __BITS(25,24), /* sel */ 156 SUNXI_CCU_DIV_POWER_OF_TWO), 157 158 SUNXI_CCU_DIV(A80_CLK_AHB1, "ahb1", ahb1_parents, 159 AHB1_CLK_CFG_REG, /* reg */ 160 __BITS(1,0), /* div */ 161 __BITS(25,24), /* sel */ 162 SUNXI_CCU_DIV_POWER_OF_TWO), 163 164 SUNXI_CCU_DIV(A80_CLK_AHB2, "ahb2", ahb2_parents, 165 AHB2_CLK_CFG_REG, /* reg */ 166 __BITS(1,0), /* div */ 167 __BITS(25,24), /* sel */ 168 SUNXI_CCU_DIV_POWER_OF_TWO), 169 170 SUNXI_CCU_DIV(A80_CLK_APB0, "apb0", apb_parents, 171 APB0_CLK_CFG_REG, /* reg */ 172 __BITS(1,0), /* div */ 173 __BIT(24), /* sel */ 174 SUNXI_CCU_DIV_POWER_OF_TWO), 175 176 SUNXI_CCU_NM(A80_CLK_APB1, "apb1", apb_parents, 177 APB1_CLK_CFG_REG, /* reg */ 178 __BITS(17,16), /* n */ 179 __BITS(4,0), /* m */ 180 __BIT(24), /* sel */ 181 0, /* enable */ 182 SUNXI_CCU_NM_POWER_OF_TWO), 183 184 SUNXI_CCU_NM(A80_CLK_MMC0, "mmc0", mmc_parents, 185 SDMMC0_CLK_REG, /* reg */ 186 __BITS(17,16), /* n */ 187 __BITS(3,0), /* m */ 188 __BITS(27,24), /* sel */ 189 __BIT(31), /* enable */ 190 SUNXI_CCU_NM_POWER_OF_TWO), 191 SUNXI_CCU_PHASE(A80_CLK_MMC0_SAMPLE, "mmc0_sample", "mmc0", 192 SDMMC0_CLK_REG, __BITS(22,20)), 193 SUNXI_CCU_PHASE(A80_CLK_MMC0_OUTPUT, "mmc0_output", "mmc0", 194 SDMMC0_CLK_REG, __BITS(10,8)), 195 SUNXI_CCU_NM(A80_CLK_MMC1, "mmc1", mmc_parents, 196 SDMMC1_CLK_REG, /* reg */ 197 __BITS(17,16), /* n */ 198 __BITS(3,0), /* m */ 199 __BITS(27,24), /* sel */ 200 __BIT(31), /* enable */ 201 SUNXI_CCU_NM_POWER_OF_TWO), 202 SUNXI_CCU_PHASE(A80_CLK_MMC1_SAMPLE, "mmc1_sample", "mmc1", 203 SDMMC1_CLK_REG, __BITS(22,20)), 204 SUNXI_CCU_PHASE(A80_CLK_MMC1_OUTPUT, "mmc1_output", "mmc1", 205 SDMMC1_CLK_REG, __BITS(10,8)), 206 SUNXI_CCU_NM(A80_CLK_MMC2, "mmc2", mmc_parents, 207 SDMMC2_CLK_REG, /* reg */ 208 __BITS(17,16), /* n */ 209 __BITS(3,0), /* m */ 210 __BITS(27,24), /* sel */ 211 __BIT(31), /* enable */ 212 SUNXI_CCU_NM_POWER_OF_TWO), 213 SUNXI_CCU_PHASE(A80_CLK_MMC2_SAMPLE, "mmc2_sample", "mmc2", 214 SDMMC2_CLK_REG, __BITS(22,20)), 215 SUNXI_CCU_PHASE(A80_CLK_MMC2_OUTPUT, "mmc2_output", "mmc2", 216 SDMMC2_CLK_REG, __BITS(10,8)), 217 218 SUNXI_CCU_GATE(A80_CLK_BUS_FD, "ahb0-fd", "ahb0", 219 BUS_CLK_GATING_REG0, 0), 220 SUNXI_CCU_GATE(A80_CLK_BUS_GPU_CTRL, "ahb0-gpu-ctrl", "ahb0", 221 BUS_CLK_GATING_REG0, 3), 222 SUNXI_CCU_GATE(A80_CLK_BUS_SS, "ahb0-ss", "ahb0", 223 BUS_CLK_GATING_REG0, 5), 224 SUNXI_CCU_GATE(A80_CLK_BUS_MMC, "ahb0-mmc", "ahb0", 225 BUS_CLK_GATING_REG0, 8), 226 SUNXI_CCU_GATE(A80_CLK_BUS_NAND1, "ahb0-nand1", "ahb0", 227 BUS_CLK_GATING_REG0, 12), 228 SUNXI_CCU_GATE(A80_CLK_BUS_NAND0, "ahb0-nand0", "ahb0", 229 BUS_CLK_GATING_REG0, 13), 230 SUNXI_CCU_GATE(A80_CLK_BUS_TS, "ahb0-ts", "ahb0", 231 BUS_CLK_GATING_REG0, 18), 232 SUNXI_CCU_GATE(A80_CLK_BUS_SPI0, "ahb0-spi0", "ahb0", 233 BUS_CLK_GATING_REG0, 20), 234 SUNXI_CCU_GATE(A80_CLK_BUS_SPI1, "ahb0-spi1", "ahb0", 235 BUS_CLK_GATING_REG0, 21), 236 SUNXI_CCU_GATE(A80_CLK_BUS_SPI2, "ahb0-spi2", "ahb0", 237 BUS_CLK_GATING_REG0, 22), 238 SUNXI_CCU_GATE(A80_CLK_BUS_SPI3, "ahb0-spi3", "ahb0", 239 BUS_CLK_GATING_REG0, 23), 240 241 SUNXI_CCU_GATE(A80_CLK_BUS_USB, "ahb1-usb", "ahb1", 242 BUS_CLK_GATING_REG1, 1), 243 SUNXI_CCU_GATE(A80_CLK_BUS_MSGBOX, "ahb1-msgbox", "ahb1", 244 BUS_CLK_GATING_REG1, 21), 245 SUNXI_CCU_GATE(A80_CLK_BUS_SPINLOCK, "ahb1-spinlock", "ahb1", 246 BUS_CLK_GATING_REG1, 22), 247 SUNXI_CCU_GATE(A80_CLK_BUS_HSTIMER, "ahb1-hstimer", "ahb1", 248 BUS_CLK_GATING_REG1, 23), 249 SUNXI_CCU_GATE(A80_CLK_BUS_DMA, "ahb1-dma", "ahb1", 250 BUS_CLK_GATING_REG1, 24), 251 252 SUNXI_CCU_GATE(A80_CLK_BUS_LCD0, "ahb2-lcd0", "ahb2", 253 BUS_CLK_GATING_REG2, 0), 254 SUNXI_CCU_GATE(A80_CLK_BUS_LCD1, "ahb2-lcd1", "ahb2", 255 BUS_CLK_GATING_REG2, 1), 256 SUNXI_CCU_GATE(A80_CLK_BUS_CSI, "ahb2-csi", "ahb2", 257 BUS_CLK_GATING_REG2, 4), 258 SUNXI_CCU_GATE(A80_CLK_BUS_DE, "ahb2-de", "ahb2", 259 BUS_CLK_GATING_REG2, 7), 260 SUNXI_CCU_GATE(A80_CLK_BUS_MP, "ahb2-mp", "ahb2", 261 BUS_CLK_GATING_REG2, 8), 262 263 SUNXI_CCU_GATE(A80_CLK_BUS_PIO, "apb0-pio", "apb0", 264 BUS_CLK_GATING_REG3, 5), 265 SUNXI_CCU_GATE(A80_CLK_BUS_LRADC, "apb0-lradc", "apb0", 266 BUS_CLK_GATING_REG3, 15), 267 SUNXI_CCU_GATE(A80_CLK_BUS_GPADC, "apb0-gpadc", "apb0", 268 BUS_CLK_GATING_REG3, 17), 269 270 SUNXI_CCU_GATE(A80_CLK_BUS_I2C0, "apb1-i2c0", "apb1", 271 BUS_CLK_GATING_REG4, 0), 272 SUNXI_CCU_GATE(A80_CLK_BUS_I2C1, "apb1-i2c1", "apb1", 273 BUS_CLK_GATING_REG4, 1), 274 SUNXI_CCU_GATE(A80_CLK_BUS_I2C2, "apb1-i2c2", "apb1", 275 BUS_CLK_GATING_REG4, 2), 276 SUNXI_CCU_GATE(A80_CLK_BUS_I2C3, "apb1-i2c3", "apb1", 277 BUS_CLK_GATING_REG4, 3), 278 SUNXI_CCU_GATE(A80_CLK_BUS_I2C4, "apb1-i2c4", "apb1", 279 BUS_CLK_GATING_REG4, 4), 280 SUNXI_CCU_GATE(A80_CLK_BUS_UART0, "apb1-uart0", "apb1", 281 BUS_CLK_GATING_REG4, 16), 282 SUNXI_CCU_GATE(A80_CLK_BUS_UART1, "apb1-uart1", "apb1", 283 BUS_CLK_GATING_REG4, 17), 284 SUNXI_CCU_GATE(A80_CLK_BUS_UART2, "apb1-uart2", "apb1", 285 BUS_CLK_GATING_REG4, 18), 286 SUNXI_CCU_GATE(A80_CLK_BUS_UART3, "apb1-uart3", "apb1", 287 BUS_CLK_GATING_REG4, 19), 288 SUNXI_CCU_GATE(A80_CLK_BUS_UART4, "apb1-uart4", "apb1", 289 BUS_CLK_GATING_REG4, 20), 290 SUNXI_CCU_GATE(A80_CLK_BUS_UART5, "apb1-uart5", "apb1", 291 BUS_CLK_GATING_REG4, 21), 292 }; 293 294 static int 295 sun9i_a80_ccu_match(device_t parent, cfdata_t cf, void *aux) 296 { 297 struct fdt_attach_args * const faa = aux; 298 299 return of_match_compatible(faa->faa_phandle, compatible); 300 } 301 302 static void 303 sun9i_a80_ccu_attach(device_t parent, device_t self, void *aux) 304 { 305 struct sunxi_ccu_softc * const sc = device_private(self); 306 struct fdt_attach_args * const faa = aux; 307 308 sc->sc_dev = self; 309 sc->sc_phandle = faa->faa_phandle; 310 sc->sc_bst = faa->faa_bst; 311 312 sc->sc_resets = sun9i_a80_ccu_resets; 313 sc->sc_nresets = __arraycount(sun9i_a80_ccu_resets); 314 315 sc->sc_clks = sun9i_a80_ccu_clks; 316 sc->sc_nclks = __arraycount(sun9i_a80_ccu_clks); 317 318 if (sunxi_ccu_attach(sc) != 0) 319 return; 320 321 aprint_naive("\n"); 322 aprint_normal(": A80 CCU\n"); 323 324 sunxi_ccu_print(sc); 325 } 326