1 /* $NetBSD: sun50i_a64_ccu.c,v 1.3 2017/09/07 23:19:45 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: sun50i_a64_ccu.c,v 1.3 2017/09/07 23:19:45 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/sun50i_a64_ccu.h> 42 43 #define PLL_CPUX_CTRL_REG 0x000 44 #define PLL_AUDIO_CTRL_REG 0x008 45 #define PLL_PERIPH0_CTRL_REG 0x028 46 #define PLL_PERIPH1_CTRL_REG 0x02c 47 #define AHB1_APB1_CFG_REG 0x054 48 #define APB2_CFG_REG 0x058 49 #define AHB2_CFG_REG 0x05c 50 #define BUS_CLK_GATING_REG0 0x060 51 #define BUS_CLK_GATING_REG1 0x064 52 #define BUS_CLK_GATING_REG2 0x068 53 #define BUS_CLK_GATING_REG3 0x06c 54 #define BUS_CLK_GATING_REG4 0x070 55 #define SDMMC0_CLK_REG 0x088 56 #define SDMMC1_CLK_REG 0x08c 57 #define SDMMC2_CLK_REG 0x090 58 #define USBPHY_CFG_REG 0x0cc 59 #define DRAM_CFG_REG 0x0f4 60 #define MBUS_RST_REG 0x0fc 61 #define AC_DIG_CLK_REG 0x140 62 #define BUS_SOFT_RST_REG0 0x2c0 63 #define BUS_SOFT_RST_REG1 0x2c4 64 #define BUS_SOFT_RST_REG2 0x2c8 65 #define BUS_SOFT_RST_REG3 0x2d0 66 #define BUS_SOFT_RST_REG4 0x2d8 67 68 static int sun50i_a64_ccu_match(device_t, cfdata_t, void *); 69 static void sun50i_a64_ccu_attach(device_t, device_t, void *); 70 71 static const char * const compatible[] = { 72 "allwinner,sun50i-a64-ccu", 73 NULL 74 }; 75 76 CFATTACH_DECL_NEW(sunxi_a64_ccu, sizeof(struct sunxi_ccu_softc), 77 sun50i_a64_ccu_match, sun50i_a64_ccu_attach, NULL, NULL); 78 79 static struct sunxi_ccu_reset sun50i_a64_ccu_resets[] = { 80 SUNXI_CCU_RESET(A64_RST_USB_PHY0, USBPHY_CFG_REG, 0), 81 SUNXI_CCU_RESET(A64_RST_USB_PHY1, USBPHY_CFG_REG, 1), 82 SUNXI_CCU_RESET(A64_RST_USB_HSIC, USBPHY_CFG_REG, 2), 83 84 SUNXI_CCU_RESET(A64_RST_DRAM, DRAM_CFG_REG, 31), 85 86 SUNXI_CCU_RESET(A64_RST_MBUS, MBUS_RST_REG, 31), 87 88 SUNXI_CCU_RESET(A64_RST_BUS_MIPI_DSI, BUS_SOFT_RST_REG0, 1), 89 SUNXI_CCU_RESET(A64_RST_BUS_CE, BUS_SOFT_RST_REG0, 5), 90 SUNXI_CCU_RESET(A64_RST_BUS_DMA, BUS_SOFT_RST_REG0, 6), 91 SUNXI_CCU_RESET(A64_RST_BUS_MMC0, BUS_SOFT_RST_REG0, 8), 92 SUNXI_CCU_RESET(A64_RST_BUS_MMC1, BUS_SOFT_RST_REG0, 9), 93 SUNXI_CCU_RESET(A64_RST_BUS_MMC2, BUS_SOFT_RST_REG0, 10), 94 SUNXI_CCU_RESET(A64_RST_BUS_NAND, BUS_SOFT_RST_REG0, 13), 95 SUNXI_CCU_RESET(A64_RST_BUS_DRAM, BUS_SOFT_RST_REG0, 14), 96 SUNXI_CCU_RESET(A64_RST_BUS_EMAC, BUS_SOFT_RST_REG0, 17), 97 SUNXI_CCU_RESET(A64_RST_BUS_TS, BUS_SOFT_RST_REG0, 18), 98 SUNXI_CCU_RESET(A64_RST_BUS_HSTIMER, BUS_SOFT_RST_REG0, 19), 99 SUNXI_CCU_RESET(A64_RST_BUS_SPI0, BUS_SOFT_RST_REG0, 20), 100 SUNXI_CCU_RESET(A64_RST_BUS_SPI1, BUS_SOFT_RST_REG0, 21), 101 SUNXI_CCU_RESET(A64_RST_BUS_OTG, BUS_SOFT_RST_REG0, 23), 102 SUNXI_CCU_RESET(A64_RST_BUS_EHCI0, BUS_SOFT_RST_REG0, 24), 103 SUNXI_CCU_RESET(A64_RST_BUS_EHCI1, BUS_SOFT_RST_REG0, 25), 104 SUNXI_CCU_RESET(A64_RST_BUS_OHCI0, BUS_SOFT_RST_REG0, 28), 105 SUNXI_CCU_RESET(A64_RST_BUS_OHCI1, BUS_SOFT_RST_REG0, 29), 106 107 SUNXI_CCU_RESET(A64_RST_BUS_VE, BUS_SOFT_RST_REG1, 0), 108 SUNXI_CCU_RESET(A64_RST_BUS_TCON0, BUS_SOFT_RST_REG1, 3), 109 SUNXI_CCU_RESET(A64_RST_BUS_TCON1, BUS_SOFT_RST_REG1, 4), 110 SUNXI_CCU_RESET(A64_RST_BUS_DEINTERLACE, BUS_SOFT_RST_REG1, 5), 111 SUNXI_CCU_RESET(A64_RST_BUS_CSI, BUS_SOFT_RST_REG1, 8), 112 SUNXI_CCU_RESET(A64_RST_BUS_HDMI0, BUS_SOFT_RST_REG1, 10), 113 SUNXI_CCU_RESET(A64_RST_BUS_HDMI1, BUS_SOFT_RST_REG1, 11), 114 SUNXI_CCU_RESET(A64_RST_BUS_DE, BUS_SOFT_RST_REG1, 12), 115 SUNXI_CCU_RESET(A64_RST_BUS_GPU, BUS_SOFT_RST_REG1, 20), 116 SUNXI_CCU_RESET(A64_RST_BUS_MSGBOX, BUS_SOFT_RST_REG1, 21), 117 SUNXI_CCU_RESET(A64_RST_BUS_SPINLOCK, BUS_SOFT_RST_REG1, 22), 118 SUNXI_CCU_RESET(A64_RST_BUS_DBG, BUS_SOFT_RST_REG1, 31), 119 120 SUNXI_CCU_RESET(A64_RST_BUS_LVDS, BUS_SOFT_RST_REG2, 0), 121 122 SUNXI_CCU_RESET(A64_RST_BUS_CODEC, BUS_SOFT_RST_REG3, 0), 123 SUNXI_CCU_RESET(A64_RST_BUS_SPDIF, BUS_SOFT_RST_REG3, 1), 124 SUNXI_CCU_RESET(A64_RST_BUS_THS, BUS_SOFT_RST_REG3, 8), 125 SUNXI_CCU_RESET(A64_RST_BUS_I2S0, BUS_SOFT_RST_REG3, 12), 126 SUNXI_CCU_RESET(A64_RST_BUS_I2S1, BUS_SOFT_RST_REG3, 13), 127 SUNXI_CCU_RESET(A64_RST_BUS_I2S2, BUS_SOFT_RST_REG3, 14), 128 129 SUNXI_CCU_RESET(A64_RST_BUS_I2C0, BUS_SOFT_RST_REG4, 0), 130 SUNXI_CCU_RESET(A64_RST_BUS_I2C1, BUS_SOFT_RST_REG4, 1), 131 SUNXI_CCU_RESET(A64_RST_BUS_I2C2, BUS_SOFT_RST_REG4, 2), 132 SUNXI_CCU_RESET(A64_RST_BUS_SCR, BUS_SOFT_RST_REG4, 5), 133 SUNXI_CCU_RESET(A64_RST_BUS_UART0, BUS_SOFT_RST_REG4, 16), 134 SUNXI_CCU_RESET(A64_RST_BUS_UART1, BUS_SOFT_RST_REG4, 17), 135 SUNXI_CCU_RESET(A64_RST_BUS_UART2, BUS_SOFT_RST_REG4, 18), 136 SUNXI_CCU_RESET(A64_RST_BUS_UART3, BUS_SOFT_RST_REG4, 19), 137 }; 138 139 static const char *ahb1_parents[] = { "losc", "hosc", "axi", "pll_periph0" }; 140 static const char *ahb2_parents[] = { "ahb1", "pll_periph0" }; 141 static const char *apb1_parents[] = { "ahb1" }; 142 static const char *apb2_parents[] = { "losc", "hosc", "pll_periph0" }; 143 static const char *mod_parents[] = { "hosc", "pll_periph0", "pll_periph1" }; 144 145 static struct sunxi_ccu_clk sun50i_a64_ccu_clks[] = { 146 SUNXI_CCU_NKMP(A64_CLK_PLL_PERIPH0, "pll_periph0", "hosc", 147 PLL_PERIPH0_CTRL_REG, /* reg */ 148 __BITS(12,8), /* n */ 149 __BITS(5,4), /* k */ 150 0, /* m */ 151 __BITS(17,16), /* p */ 152 __BIT(31), /* enable */ 153 SUNXI_CCU_NKMP_DIVIDE_BY_TWO), 154 155 SUNXI_CCU_PREDIV(A64_CLK_AHB1, "ahb1", ahb1_parents, 156 AHB1_APB1_CFG_REG, /* reg */ 157 __BITS(7,6), /* prediv */ 158 __BIT(3), /* prediv_sel */ 159 __BITS(5,4), /* div */ 160 __BITS(13,12), /* sel */ 161 SUNXI_CCU_PREDIV_POWER_OF_TWO), 162 163 SUNXI_CCU_PREDIV(A64_CLK_AHB2, "ahb2", ahb2_parents, 164 AHB2_CFG_REG, /* reg */ 165 0, /* prediv */ 166 __BIT(1), /* prediv_sel */ 167 0, /* div */ 168 __BITS(1,0), /* sel */ 169 SUNXI_CCU_PREDIV_DIVIDE_BY_TWO), 170 171 SUNXI_CCU_DIV(A64_CLK_APB1, "apb1", apb1_parents, 172 AHB1_APB1_CFG_REG, /* reg */ 173 __BITS(9,8), /* div */ 174 0, /* sel */ 175 SUNXI_CCU_DIV_POWER_OF_TWO|SUNXI_CCU_DIV_ZERO_IS_ONE), 176 177 SUNXI_CCU_NM(A64_CLK_APB2, "apb2", apb2_parents, 178 APB2_CFG_REG, /* reg */ 179 __BITS(17,16), /* n */ 180 __BITS(4,0), /* m */ 181 __BITS(25,24), /* sel */ 182 0, /* enable */ 183 SUNXI_CCU_NM_POWER_OF_TWO), 184 185 SUNXI_CCU_NM(A64_CLK_MMC0, "mmc0", mod_parents, 186 SDMMC0_CLK_REG, __BITS(17, 16), __BITS(3,0), __BITS(25, 24), __BIT(31), 187 SUNXI_CCU_NM_POWER_OF_TWO|SUNXI_CCU_NM_ROUND_DOWN), 188 SUNXI_CCU_NM(A64_CLK_MMC1, "mmc1", mod_parents, 189 SDMMC1_CLK_REG, __BITS(17, 16), __BITS(3,0), __BITS(25, 24), __BIT(31), 190 SUNXI_CCU_NM_POWER_OF_TWO|SUNXI_CCU_NM_ROUND_DOWN), 191 SUNXI_CCU_NM(A64_CLK_MMC2, "mmc2", mod_parents, 192 SDMMC2_CLK_REG, __BITS(17, 16), __BITS(3,0), __BITS(25, 24), __BIT(31), 193 SUNXI_CCU_NM_POWER_OF_TWO|SUNXI_CCU_NM_ROUND_DOWN), 194 195 SUNXI_CCU_GATE(A64_CLK_BUS_MIPI_DSI, "bus-mipi-dsi", "ahb1", 196 BUS_CLK_GATING_REG0, 1), 197 SUNXI_CCU_GATE(A64_CLK_BUS_CE, "bus-ce", "ahb1", 198 BUS_CLK_GATING_REG0, 5), 199 SUNXI_CCU_GATE(A64_CLK_BUS_DMA, "bus-dma", "ahb1", 200 BUS_CLK_GATING_REG0, 6), 201 SUNXI_CCU_GATE(A64_CLK_BUS_MMC0, "bus-mmc0", "ahb1", 202 BUS_CLK_GATING_REG0, 8), 203 SUNXI_CCU_GATE(A64_CLK_BUS_MMC1, "bus-mmc1", "ahb1", 204 BUS_CLK_GATING_REG0, 9), 205 SUNXI_CCU_GATE(A64_CLK_BUS_MMC2, "bus-mmc2", "ahb1", 206 BUS_CLK_GATING_REG0, 10), 207 SUNXI_CCU_GATE(A64_CLK_BUS_NAND, "bus-nand", "ahb1", 208 BUS_CLK_GATING_REG0, 13), 209 SUNXI_CCU_GATE(A64_CLK_BUS_DRAM, "bus-dram", "ahb1", 210 BUS_CLK_GATING_REG0, 14), 211 SUNXI_CCU_GATE(A64_CLK_BUS_EMAC, "bus-emac", "ahb2", 212 BUS_CLK_GATING_REG0, 17), 213 SUNXI_CCU_GATE(A64_CLK_BUS_TS, "bus-ts", "ahb1", 214 BUS_CLK_GATING_REG0, 18), 215 SUNXI_CCU_GATE(A64_CLK_BUS_HSTIMER, "bus-hstimer", "ahb1", 216 BUS_CLK_GATING_REG0, 19), 217 SUNXI_CCU_GATE(A64_CLK_BUS_SPI0, "bus-spi0", "ahb1", 218 BUS_CLK_GATING_REG0, 20), 219 SUNXI_CCU_GATE(A64_CLK_BUS_SPI1, "bus-spi1", "ahb1", 220 BUS_CLK_GATING_REG0, 21), 221 SUNXI_CCU_GATE(A64_CLK_BUS_OTG, "bus-otg", "ahb1", 222 BUS_CLK_GATING_REG0, 23), 223 SUNXI_CCU_GATE(A64_CLK_BUS_EHCI0, "bus-ehci0", "ahb1", 224 BUS_CLK_GATING_REG0, 24), 225 SUNXI_CCU_GATE(A64_CLK_BUS_EHCI1, "bus-ehci1", "ahb2", 226 BUS_CLK_GATING_REG0, 25), 227 SUNXI_CCU_GATE(A64_CLK_BUS_OHCI0, "bus-ohci0", "ahb1", 228 BUS_CLK_GATING_REG0, 28), 229 SUNXI_CCU_GATE(A64_CLK_BUS_OHCI1, "bus-ohci1", "ahb2", 230 BUS_CLK_GATING_REG0, 29), 231 232 SUNXI_CCU_GATE(A64_CLK_BUS_VE, "bus-ve", "ahb1", 233 BUS_CLK_GATING_REG1, 0), 234 SUNXI_CCU_GATE(A64_CLK_BUS_TCON0, "bus-tcon0", "ahb1", 235 BUS_CLK_GATING_REG1, 3), 236 SUNXI_CCU_GATE(A64_CLK_BUS_TCON1, "bus-tcon1", "ahb1", 237 BUS_CLK_GATING_REG1, 4), 238 SUNXI_CCU_GATE(A64_CLK_BUS_DEINTERLACE, "bus-deinterlace", "ahb1", 239 BUS_CLK_GATING_REG1, 5), 240 SUNXI_CCU_GATE(A64_CLK_BUS_CSI, "bus-csi", "ahb1", 241 BUS_CLK_GATING_REG1, 8), 242 SUNXI_CCU_GATE(A64_CLK_BUS_HDMI, "bus-hdmi", "ahb1", 243 BUS_CLK_GATING_REG1, 10), 244 SUNXI_CCU_GATE(A64_CLK_BUS_DE, "bus-de", "ahb1", 245 BUS_CLK_GATING_REG1, 12), 246 SUNXI_CCU_GATE(A64_CLK_BUS_GPU, "bus-gpu", "ahb1", 247 BUS_CLK_GATING_REG1, 20), 248 SUNXI_CCU_GATE(A64_CLK_BUS_MSGBOX, "bus-msgbox", "ahb1", 249 BUS_CLK_GATING_REG1, 21), 250 SUNXI_CCU_GATE(A64_CLK_BUS_SPINLOCK, "bus-spinlock", "ahb1", 251 BUS_CLK_GATING_REG1, 22), 252 253 254 SUNXI_CCU_GATE(A64_CLK_BUS_CODEC, "bus-codec", "apb1", 255 BUS_CLK_GATING_REG3, 0), 256 SUNXI_CCU_GATE(A64_CLK_BUS_SPDIF, "bus-spdif", "apb1", 257 BUS_CLK_GATING_REG3, 1), 258 SUNXI_CCU_GATE(A64_CLK_BUS_PIO, "bus-pio", "apb1", 259 BUS_CLK_GATING_REG3, 5), 260 SUNXI_CCU_GATE(A64_CLK_BUS_THS, "bus-ths", "apb1", 261 BUS_CLK_GATING_REG3, 8), 262 SUNXI_CCU_GATE(A64_CLK_BUS_I2S0, "bus-i2s0", "apb1", 263 BUS_CLK_GATING_REG3, 12), 264 SUNXI_CCU_GATE(A64_CLK_BUS_I2S1, "bus-i2s1", "apb1", 265 BUS_CLK_GATING_REG3, 13), 266 SUNXI_CCU_GATE(A64_CLK_BUS_I2S2, "bus-i2s2", "apb1", 267 BUS_CLK_GATING_REG3, 14), 268 269 SUNXI_CCU_GATE(A64_CLK_BUS_I2C0, "bus-i2c0", "apb2", 270 BUS_CLK_GATING_REG4, 0), 271 SUNXI_CCU_GATE(A64_CLK_BUS_I2C1, "bus-i2c1", "apb2", 272 BUS_CLK_GATING_REG4, 1), 273 SUNXI_CCU_GATE(A64_CLK_BUS_I2C2, "bus-i2c2", "apb2", 274 BUS_CLK_GATING_REG4, 2), 275 SUNXI_CCU_GATE(A64_CLK_BUS_SCR, "bus-scr", "apb2", 276 BUS_CLK_GATING_REG4, 5), 277 SUNXI_CCU_GATE(A64_CLK_BUS_UART0, "bus-uart0", "apb2", 278 BUS_CLK_GATING_REG4, 16), 279 SUNXI_CCU_GATE(A64_CLK_BUS_UART1, "bus-uart1", "apb2", 280 BUS_CLK_GATING_REG4, 17), 281 SUNXI_CCU_GATE(A64_CLK_BUS_UART2, "bus-uart2", "apb2", 282 BUS_CLK_GATING_REG4, 18), 283 SUNXI_CCU_GATE(A64_CLK_BUS_UART3, "bus-uart3", "apb2", 284 BUS_CLK_GATING_REG4, 19), 285 SUNXI_CCU_GATE(A64_CLK_BUS_UART4, "bus-uart4", "apb2", 286 BUS_CLK_GATING_REG4, 20), 287 288 SUNXI_CCU_GATE(A64_CLK_USB_PHY0, "usb-phy0", "hosc", 289 USBPHY_CFG_REG, 8), 290 SUNXI_CCU_GATE(A64_CLK_USB_PHY1, "usb-phy1", "hosc", 291 USBPHY_CFG_REG, 9), 292 SUNXI_CCU_GATE(A64_CLK_USB_HSIC, "usb-hsic", "hosc", 293 USBPHY_CFG_REG, 10), 294 SUNXI_CCU_GATE(A64_CLK_USB_HSIC_12M, "usb-hsic-12m", "hosc", 295 USBPHY_CFG_REG, 11), 296 SUNXI_CCU_GATE(A64_CLK_USB_OHCI0, "usb-ohci0", "hosc", 297 USBPHY_CFG_REG, 16), 298 SUNXI_CCU_GATE(A64_CLK_USB_OHCI1, "usb-ohci1", "usb-ohci0", 299 USBPHY_CFG_REG, 17), 300 }; 301 302 static int 303 sun50i_a64_ccu_match(device_t parent, cfdata_t cf, void *aux) 304 { 305 struct fdt_attach_args * const faa = aux; 306 307 return of_match_compatible(faa->faa_phandle, compatible); 308 } 309 310 static void 311 sun50i_a64_ccu_attach(device_t parent, device_t self, void *aux) 312 { 313 struct sunxi_ccu_softc * const sc = device_private(self); 314 struct fdt_attach_args * const faa = aux; 315 316 sc->sc_dev = self; 317 sc->sc_phandle = faa->faa_phandle; 318 sc->sc_bst = faa->faa_bst; 319 320 sc->sc_resets = sun50i_a64_ccu_resets; 321 sc->sc_nresets = __arraycount(sun50i_a64_ccu_resets); 322 323 sc->sc_clks = sun50i_a64_ccu_clks; 324 sc->sc_nclks = __arraycount(sun50i_a64_ccu_clks); 325 326 if (sunxi_ccu_attach(sc) != 0) 327 return; 328 329 aprint_naive("\n"); 330 aprint_normal(": A64 CCU\n"); 331 332 sunxi_ccu_print(sc); 333 } 334