1 /* $NetBSD: sun8i_a83t_ccu.c,v 1.5 2017/10/28 22:59:27 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 2017 Jared McNeill <jmcneill@invisible.ca> 5 * Copyright (c) 2017 Emmanuel Vadot <manu@freebsd.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 32 __KERNEL_RCSID(1, "$NetBSD: sun8i_a83t_ccu.c,v 1.5 2017/10/28 22:59:27 jmcneill Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/bus.h> 36 #include <sys/device.h> 37 #include <sys/systm.h> 38 39 #include <dev/fdt/fdtvar.h> 40 41 #include <arm/sunxi/sunxi_ccu.h> 42 #include <arm/sunxi/sun8i_a83t_ccu.h> 43 44 #define PLL_PERIPH_CTRL_REG 0x028 45 #define AHB1_APB1_CFG_REG 0x054 46 #define APB2_CFG_REG 0x058 47 #define BUS_CLK_GATING_REG0 0x060 48 #define BUS_CLK_GATING_REG1 0x064 49 #define BUS_CLK_GATING_REG2 0x068 50 #define BUS_CLK_GATING_REG3 0x06c 51 #define SDMMC0_CLK_REG 0x088 52 #define SDMMC1_CLK_REG 0x08c 53 #define SDMMC2_CLK_REG 0x090 54 #define SDMMC2_CLK_MODE_SELECT __BIT(30) 55 #define USBPHY_CFG_REG 0x0cc 56 #define MBUS_RST_REG 0x0fc 57 #define BUS_SOFT_RST_REG0 0x2c0 58 #define BUS_SOFT_RST_REG1 0x2c4 59 #define BUS_SOFT_RST_REG2 0x2c8 60 #define BUS_SOFT_RST_REG3 0x2d0 61 #define BUS_SOFT_RST_REG4 0x2d8 62 63 static int sun8i_a83t_ccu_match(device_t, cfdata_t, void *); 64 static void sun8i_a83t_ccu_attach(device_t, device_t, void *); 65 66 static const char * const compatible[] = { 67 "allwinner,sun8i-a83t-ccu", 68 NULL 69 }; 70 71 CFATTACH_DECL_NEW(sunxi_a83t_ccu, sizeof(struct sunxi_ccu_softc), 72 sun8i_a83t_ccu_match, sun8i_a83t_ccu_attach, NULL, NULL); 73 74 static struct sunxi_ccu_reset sun8i_a83t_ccu_resets[] = { 75 SUNXI_CCU_RESET(A83T_RST_USB_PHY0, USBPHY_CFG_REG, 0), 76 SUNXI_CCU_RESET(A83T_RST_USB_PHY1, USBPHY_CFG_REG, 1), 77 78 SUNXI_CCU_RESET(A83T_RST_MBUS, MBUS_RST_REG, 31), 79 80 SUNXI_CCU_RESET(A83T_RST_BUS_DMA, BUS_SOFT_RST_REG0, 6), 81 SUNXI_CCU_RESET(A83T_RST_BUS_MMC0, BUS_SOFT_RST_REG0, 8), 82 SUNXI_CCU_RESET(A83T_RST_BUS_MMC1, BUS_SOFT_RST_REG0, 9), 83 SUNXI_CCU_RESET(A83T_RST_BUS_MMC2, BUS_SOFT_RST_REG0, 10), 84 SUNXI_CCU_RESET(A83T_RST_BUS_NAND, BUS_SOFT_RST_REG0, 13), 85 SUNXI_CCU_RESET(A83T_RST_BUS_DRAM, BUS_SOFT_RST_REG0, 14), 86 SUNXI_CCU_RESET(A83T_RST_BUS_EMAC, BUS_SOFT_RST_REG0, 17), 87 SUNXI_CCU_RESET(A83T_RST_BUS_HSTIMER, BUS_SOFT_RST_REG0, 19), 88 SUNXI_CCU_RESET(A83T_RST_BUS_SPI0, BUS_SOFT_RST_REG0, 20), 89 SUNXI_CCU_RESET(A83T_RST_BUS_SPI1, BUS_SOFT_RST_REG0, 21), 90 SUNXI_CCU_RESET(A83T_RST_BUS_OTG, BUS_SOFT_RST_REG0, 23), 91 SUNXI_CCU_RESET(A83T_RST_BUS_EHCI0, BUS_SOFT_RST_REG0, 26), 92 SUNXI_CCU_RESET(A83T_RST_BUS_EHCI1, BUS_SOFT_RST_REG0, 27), 93 SUNXI_CCU_RESET(A83T_RST_BUS_OHCI0, BUS_SOFT_RST_REG0, 29), 94 95 SUNXI_CCU_RESET(A83T_RST_BUS_VE, BUS_SOFT_RST_REG1, 0), 96 SUNXI_CCU_RESET(A83T_RST_BUS_TCON0, BUS_SOFT_RST_REG1, 3), 97 SUNXI_CCU_RESET(A83T_RST_BUS_TCON1, BUS_SOFT_RST_REG1, 4), 98 SUNXI_CCU_RESET(A83T_RST_BUS_CSI, BUS_SOFT_RST_REG1, 8), 99 SUNXI_CCU_RESET(A83T_RST_BUS_HDMI0, BUS_SOFT_RST_REG1, 10), 100 SUNXI_CCU_RESET(A83T_RST_BUS_HDMI1, BUS_SOFT_RST_REG1, 11), 101 SUNXI_CCU_RESET(A83T_RST_BUS_DE, BUS_SOFT_RST_REG1, 12), 102 SUNXI_CCU_RESET(A83T_RST_BUS_GPU, BUS_SOFT_RST_REG1, 20), 103 SUNXI_CCU_RESET(A83T_RST_BUS_MSGBOX, BUS_SOFT_RST_REG1, 21), 104 SUNXI_CCU_RESET(A83T_RST_BUS_SPINLOCK, BUS_SOFT_RST_REG1, 22), 105 106 SUNXI_CCU_RESET(A83T_RST_BUS_SPDIF, BUS_SOFT_RST_REG3, 1), 107 SUNXI_CCU_RESET(A83T_RST_BUS_I2S0, BUS_SOFT_RST_REG3, 12), 108 SUNXI_CCU_RESET(A83T_RST_BUS_I2S1, BUS_SOFT_RST_REG3, 13), 109 SUNXI_CCU_RESET(A83T_RST_BUS_I2S2, BUS_SOFT_RST_REG3, 14), 110 111 SUNXI_CCU_RESET(A83T_RST_BUS_I2C0, BUS_SOFT_RST_REG4, 0), 112 SUNXI_CCU_RESET(A83T_RST_BUS_I2C1, BUS_SOFT_RST_REG4, 1), 113 SUNXI_CCU_RESET(A83T_RST_BUS_I2C2, BUS_SOFT_RST_REG4, 2), 114 SUNXI_CCU_RESET(A83T_RST_BUS_UART0, BUS_SOFT_RST_REG4, 16), 115 SUNXI_CCU_RESET(A83T_RST_BUS_UART1, BUS_SOFT_RST_REG4, 17), 116 SUNXI_CCU_RESET(A83T_RST_BUS_UART2, BUS_SOFT_RST_REG4, 18), 117 SUNXI_CCU_RESET(A83T_RST_BUS_UART3, BUS_SOFT_RST_REG4, 19), 118 }; 119 120 static const char *ahb1_parents[] = { "losc", "hosc", "pll_periph" }; 121 static const char *ahb2_parents[] = { "ahb1", "pll_periph" }; 122 static const char *apb1_parents[] = { "ahb1" }; 123 static const char *apb2_parents[] = { "losc", "hosc", "pll_periph" }; 124 static const char *mod_parents[] = { "hosc", "pll_periph" }; 125 126 static struct sunxi_ccu_clk sun8i_a83t_ccu_clks[] = { 127 SUNXI_CCU_NKMP(A83T_CLK_PLL_PERIPH, "pll_periph", "hosc", 128 PLL_PERIPH_CTRL_REG, /* reg */ 129 __BITS(15,8), /* n */ 130 0, /* k */ 131 __BIT(18), /* m */ 132 __BIT(16), /* p */ 133 __BIT(31), /* enable */ 134 SUNXI_CCU_NKMP_FACTOR_N_EXACT), 135 136 SUNXI_CCU_PREDIV(A83T_CLK_AHB1, "ahb1", ahb1_parents, 137 AHB1_APB1_CFG_REG, /* reg */ 138 __BITS(7,6), /* prediv */ 139 __BIT(3), /* prediv_sel */ 140 __BITS(5,4), /* div */ 141 __BITS(13,12), /* sel */ 142 SUNXI_CCU_PREDIV_POWER_OF_TWO), 143 144 SUNXI_CCU_PREDIV(A83T_CLK_AHB2, "ahb2", ahb2_parents, 145 APB2_CFG_REG, /* reg */ 146 0, /* prediv */ 147 __BIT(1), /* prediv_sel */ 148 0, /* div */ 149 __BITS(1,0), /* sel */ 150 SUNXI_CCU_PREDIV_DIVIDE_BY_TWO), 151 152 SUNXI_CCU_DIV(A83T_CLK_APB1, "apb1", apb1_parents, 153 AHB1_APB1_CFG_REG, /* reg */ 154 __BITS(9,8), /* div */ 155 0, /* sel */ 156 SUNXI_CCU_DIV_POWER_OF_TWO|SUNXI_CCU_DIV_ZERO_IS_ONE), 157 158 SUNXI_CCU_NM(A83T_CLK_APB2, "apb2", apb2_parents, 159 APB2_CFG_REG, /* reg */ 160 __BITS(17,16), /* n */ 161 __BITS(4,0), /* m */ 162 __BITS(25,24), /* sel */ 163 0, /* enable */ 164 SUNXI_CCU_NM_POWER_OF_TWO), 165 166 SUNXI_CCU_NM(A83T_CLK_MMC0, "mmc0", mod_parents, 167 SDMMC0_CLK_REG, __BITS(17, 16), __BITS(3,0), __BITS(25, 24), __BIT(31), 168 SUNXI_CCU_NM_POWER_OF_TWO|SUNXI_CCU_NM_ROUND_DOWN), 169 SUNXI_CCU_NM(A83T_CLK_MMC1, "mmc1", mod_parents, 170 SDMMC1_CLK_REG, __BITS(17, 16), __BITS(3,0), __BITS(25, 24), __BIT(31), 171 SUNXI_CCU_NM_POWER_OF_TWO|SUNXI_CCU_NM_ROUND_DOWN), 172 SUNXI_CCU_NM(A83T_CLK_MMC2, "mmc2", mod_parents, 173 SDMMC2_CLK_REG, __BITS(17, 16), __BITS(3,0), __BITS(25, 24), __BIT(31), 174 SUNXI_CCU_NM_POWER_OF_TWO|SUNXI_CCU_NM_ROUND_DOWN|SUNXI_CCU_NM_DIVIDE_BY_TWO), 175 176 SUNXI_CCU_GATE(A83T_CLK_BUS_MIPI_DSI, "bus-mipi-dsi", "ahb1", 177 BUS_CLK_GATING_REG0, 1), 178 SUNXI_CCU_GATE(A83T_CLK_BUS_SS, "bus-ss", "ahb1", 179 BUS_CLK_GATING_REG0, 5), 180 SUNXI_CCU_GATE(A83T_CLK_BUS_DMA, "bus-dma", "ahb1", 181 BUS_CLK_GATING_REG0, 6), 182 SUNXI_CCU_GATE(A83T_CLK_BUS_MMC0, "bus-mmc0", "ahb1", 183 BUS_CLK_GATING_REG0, 8), 184 SUNXI_CCU_GATE(A83T_CLK_BUS_MMC1, "bus-mmc1", "ahb1", 185 BUS_CLK_GATING_REG0, 9), 186 SUNXI_CCU_GATE(A83T_CLK_BUS_MMC2, "bus-mmc2", "ahb1", 187 BUS_CLK_GATING_REG0, 10), 188 SUNXI_CCU_GATE(A83T_CLK_BUS_NAND, "bus-nand", "ahb1", 189 BUS_CLK_GATING_REG0, 13), 190 SUNXI_CCU_GATE(A83T_CLK_BUS_DRAM, "bus-dram", "ahb1", 191 BUS_CLK_GATING_REG0, 14), 192 SUNXI_CCU_GATE(A83T_CLK_BUS_EMAC, "bus-emac", "ahb2", 193 BUS_CLK_GATING_REG0, 17), 194 SUNXI_CCU_GATE(A83T_CLK_BUS_HSTIMER, "bus-hstimer", "ahb1", 195 BUS_CLK_GATING_REG0, 19), 196 SUNXI_CCU_GATE(A83T_CLK_BUS_SPI0, "bus-spi0", "ahb1", 197 BUS_CLK_GATING_REG0, 20), 198 SUNXI_CCU_GATE(A83T_CLK_BUS_SPI1, "bus-spi1", "ahb1", 199 BUS_CLK_GATING_REG0, 21), 200 SUNXI_CCU_GATE(A83T_CLK_BUS_OTG, "bus-otg", "ahb1", 201 BUS_CLK_GATING_REG0, 24), 202 SUNXI_CCU_GATE(A83T_CLK_BUS_EHCI0, "bus-ehci0", "ahb1", 203 BUS_CLK_GATING_REG0, 26), 204 SUNXI_CCU_GATE(A83T_CLK_BUS_EHCI1, "bus-ehci1", "ahb2", 205 BUS_CLK_GATING_REG0, 27), 206 SUNXI_CCU_GATE(A83T_CLK_BUS_OHCI0, "bus-ohci0", "ahb1", 207 BUS_CLK_GATING_REG0, 29), 208 209 SUNXI_CCU_GATE(A83T_CLK_BUS_VE, "bus-ve", "ahb2", 210 BUS_CLK_GATING_REG1, 0), 211 SUNXI_CCU_GATE(A83T_CLK_BUS_TCON0, "bus-tcon0", "ahb2", 212 BUS_CLK_GATING_REG1, 4), 213 SUNXI_CCU_GATE(A83T_CLK_BUS_TCON1, "bus-tcon1", "ahb2", 214 BUS_CLK_GATING_REG1, 5), 215 SUNXI_CCU_GATE(A83T_CLK_BUS_CSI, "bus-csi", "ahb2", 216 BUS_CLK_GATING_REG1, 8), 217 SUNXI_CCU_GATE(A83T_CLK_BUS_HDMI, "bus-hdmi", "ahb2", 218 BUS_CLK_GATING_REG1, 11), 219 SUNXI_CCU_GATE(A83T_CLK_BUS_DE, "bus-de", "ahb2", 220 BUS_CLK_GATING_REG1, 12), 221 SUNXI_CCU_GATE(A83T_CLK_BUS_GPU, "bus-gpu", "ahb2", 222 BUS_CLK_GATING_REG1, 20), 223 SUNXI_CCU_GATE(A83T_CLK_BUS_MSGBOX, "bus-msgbox", "ahb2", 224 BUS_CLK_GATING_REG1, 21), 225 SUNXI_CCU_GATE(A83T_CLK_BUS_SPINLOCK, "bus-spinlock", "ahb2", 226 BUS_CLK_GATING_REG1, 22), 227 228 SUNXI_CCU_GATE(A83T_CLK_BUS_SPDIF, "bus-spdif", "apb1", 229 BUS_CLK_GATING_REG2, 1), 230 SUNXI_CCU_GATE(A83T_CLK_BUS_PIO, "bus-pio", "apb1", 231 BUS_CLK_GATING_REG2, 5), 232 SUNXI_CCU_GATE(A83T_CLK_BUS_I2S0, "bus-i2s0", "apb1", 233 BUS_CLK_GATING_REG2, 12), 234 SUNXI_CCU_GATE(A83T_CLK_BUS_I2S1, "bus-i2s1", "apb1", 235 BUS_CLK_GATING_REG2, 13), 236 SUNXI_CCU_GATE(A83T_CLK_BUS_I2S2, "bus-i2s2", "apb1", 237 BUS_CLK_GATING_REG2, 14), 238 SUNXI_CCU_GATE(A83T_CLK_BUS_TDM, "bus-tdm", "apb1", 239 BUS_CLK_GATING_REG2, 15), 240 241 SUNXI_CCU_GATE(A83T_CLK_BUS_I2C0, "bus-i2c0", "apb2", 242 BUS_CLK_GATING_REG3, 0), 243 SUNXI_CCU_GATE(A83T_CLK_BUS_I2C1, "bus-i2c1", "apb2", 244 BUS_CLK_GATING_REG3, 1), 245 SUNXI_CCU_GATE(A83T_CLK_BUS_I2C2, "bus-i2c2", "apb2", 246 BUS_CLK_GATING_REG3, 2), 247 SUNXI_CCU_GATE(A83T_CLK_BUS_UART0, "bus-uart0", "apb2", 248 BUS_CLK_GATING_REG3, 16), 249 SUNXI_CCU_GATE(A83T_CLK_BUS_UART1, "bus-uart1", "apb2", 250 BUS_CLK_GATING_REG3, 17), 251 SUNXI_CCU_GATE(A83T_CLK_BUS_UART2, "bus-uart2", "apb2", 252 BUS_CLK_GATING_REG3, 18), 253 SUNXI_CCU_GATE(A83T_CLK_BUS_UART3, "bus-uart3", "apb2", 254 BUS_CLK_GATING_REG3, 19), 255 SUNXI_CCU_GATE(A83T_CLK_BUS_UART4, "bus-uart4", "apb2", 256 BUS_CLK_GATING_REG3, 20), 257 258 SUNXI_CCU_GATE(A83T_CLK_USB_PHY0, "usb-phy0", "hosc", 259 USBPHY_CFG_REG, 8), 260 SUNXI_CCU_GATE(A83T_CLK_USB_PHY1, "usb-phy1", "hosc", 261 USBPHY_CFG_REG, 9), 262 SUNXI_CCU_GATE(A83T_CLK_USB_OHCI0, "usb-ohci0", "hosc", 263 USBPHY_CFG_REG, 16), 264 }; 265 266 static void 267 sun8i_a83t_ccu_init(struct sunxi_ccu_softc *sc) 268 { 269 uint32_t val; 270 271 /* SDMMC2 has a mode select switch. Always use "New Mode". */ 272 val = CCU_READ(sc, SDMMC2_CLK_REG); 273 val |= SDMMC2_CLK_MODE_SELECT; 274 CCU_WRITE(sc, SDMMC2_CLK_REG, val); 275 } 276 277 static int 278 sun8i_a83t_ccu_match(device_t parent, cfdata_t cf, void *aux) 279 { 280 struct fdt_attach_args * const faa = aux; 281 282 return of_match_compatible(faa->faa_phandle, compatible); 283 } 284 285 static void 286 sun8i_a83t_ccu_attach(device_t parent, device_t self, void *aux) 287 { 288 struct sunxi_ccu_softc * const sc = device_private(self); 289 struct fdt_attach_args * const faa = aux; 290 291 sc->sc_dev = self; 292 sc->sc_phandle = faa->faa_phandle; 293 sc->sc_bst = faa->faa_bst; 294 295 sc->sc_resets = sun8i_a83t_ccu_resets; 296 sc->sc_nresets = __arraycount(sun8i_a83t_ccu_resets); 297 298 sc->sc_clks = sun8i_a83t_ccu_clks; 299 sc->sc_nclks = __arraycount(sun8i_a83t_ccu_clks); 300 301 if (sunxi_ccu_attach(sc) != 0) 302 return; 303 304 aprint_naive("\n"); 305 aprint_normal(": A83T CCU\n"); 306 307 sun8i_a83t_ccu_init(sc); 308 309 sunxi_ccu_print(sc); 310 } 311