1 /*- 2 * Copyright (c) 2013 Ruslan Bukin <br@bsdpad.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 /* 28 * Vybrid Family Clock Controller Module (CCM) 29 * Chapter 10, Vybrid Reference Manual, Rev. 5, 07/2013 30 */ 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/bus.h> 38 #include <sys/kernel.h> 39 #include <sys/module.h> 40 #include <sys/malloc.h> 41 #include <sys/rman.h> 42 #include <sys/timeet.h> 43 #include <sys/timetc.h> 44 #include <sys/watchdog.h> 45 46 #include <dev/fdt/fdt_common.h> 47 #include <dev/ofw/openfirm.h> 48 #include <dev/ofw/ofw_bus.h> 49 #include <dev/ofw/ofw_bus_subr.h> 50 51 #include <machine/bus.h> 52 #include <machine/fdt.h> 53 #include <machine/cpu.h> 54 #include <machine/intr.h> 55 56 #include <arm/freescale/vybrid/vf_common.h> 57 58 #define CCM_CCR 0x00 /* Control Register */ 59 #define CCM_CSR 0x04 /* Status Register */ 60 #define CCM_CCSR 0x08 /* Clock Switcher Register */ 61 #define CCM_CACRR 0x0C /* ARM Clock Root Register */ 62 #define CCM_CSCMR1 0x10 /* Serial Clock Multiplexer Register 1 */ 63 #define CCM_CSCDR1 0x14 /* Serial Clock Divider Register 1 */ 64 #define CCM_CSCDR2 0x18 /* Serial Clock Divider Register 2 */ 65 #define CCM_CSCDR3 0x1C /* Serial Clock Divider Register 3 */ 66 #define CCM_CSCMR2 0x20 /* Serial Clock Multiplexer Register 2 */ 67 #define CCM_CTOR 0x28 /* Testing Observability Register */ 68 #define CCM_CLPCR 0x2C /* Low Power Control Register */ 69 #define CCM_CISR 0x30 /* Interrupt Status Register */ 70 #define CCM_CIMR 0x34 /* Interrupt Mask Register */ 71 #define CCM_CCOSR 0x38 /* Clock Output Source Register */ 72 #define CCM_CGPR 0x3C /* General Purpose Register */ 73 74 #define CCM_CCGRN 12 75 #define CCM_CCGR(n) (0x40 + (n * 0x04)) /* Clock Gating Register */ 76 #define CCM_CMEOR(n) (0x70 + (n * 0x70)) /* Module Enable Override Reg */ 77 #define CCM_CCPGR(n) (0x90 + (n * 0x04)) /* Platform Clock Gating Reg */ 78 79 #define CCM_CPPDSR 0x88 /* PLL PFD Disable Status Register */ 80 #define CCM_CCOWR 0x8C /* CORE Wakeup Register */ 81 82 #define PLL3_PFD4_EN (1 << 31) 83 #define PLL3_PFD3_EN (1 << 30) 84 #define PLL3_PFD2_EN (1 << 29) 85 #define PLL3_PFD1_EN (1 << 28) 86 #define PLL2_PFD4_EN (1 << 15) 87 #define PLL2_PFD3_EN (1 << 14) 88 #define PLL2_PFD2_EN (1 << 13) 89 #define PLL2_PFD1_EN (1 << 12) 90 #define PLL1_PFD4_EN (1 << 11) 91 #define PLL1_PFD3_EN (1 << 10) 92 #define PLL1_PFD2_EN (1 << 9) 93 #define PLL1_PFD1_EN (1 << 8) 94 95 /* CCM_CCR */ 96 #define FIRC_EN (1 << 16) 97 #define FXOSC_EN (1 << 12) 98 #define FXOSC_RDY (1 << 5) 99 100 /* CCM_CSCDR1 */ 101 #define ENET_TS_EN (1 << 23) 102 #define RMII_CLK_EN (1 << 24) 103 104 struct ccm_softc { 105 struct resource *res[1]; 106 bus_space_tag_t bst; 107 bus_space_handle_t bsh; 108 device_t dev; 109 }; 110 111 static struct resource_spec ccm_spec[] = { 112 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 113 { -1, 0 } 114 }; 115 116 static int 117 ccm_probe(device_t dev) 118 { 119 120 if (!ofw_bus_is_compatible(dev, "fsl,mvf600-ccm")) 121 return (ENXIO); 122 123 device_set_desc(dev, "Vybrid Family CCM Unit"); 124 return (BUS_PROBE_DEFAULT); 125 } 126 127 static int 128 ccm_attach(device_t dev) 129 { 130 struct ccm_softc *sc; 131 int reg; 132 int i; 133 134 sc = device_get_softc(dev); 135 sc->dev = dev; 136 137 if (bus_alloc_resources(dev, ccm_spec, sc->res)) { 138 device_printf(dev, "could not allocate resources\n"); 139 return (ENXIO); 140 } 141 142 /* Memory interface */ 143 sc->bst = rman_get_bustag(sc->res[0]); 144 sc->bsh = rman_get_bushandle(sc->res[0]); 145 146 /* Enable oscillator */ 147 reg = READ4(sc, CCM_CCR); 148 reg |= (FIRC_EN | FXOSC_EN); 149 WRITE4(sc, CCM_CCR, reg); 150 151 /* Wait 10 times */ 152 for (i = 0; i < 10; i++) { 153 if (READ4(sc, CCM_CSR) & FXOSC_RDY) { 154 device_printf(sc->dev, "On board oscillator is ready.\n"); 155 break; 156 } 157 158 cpufunc_nullop(); 159 } 160 161 /* Clock is on during all modes, except stop mode. */ 162 for (i = 0; i < CCM_CCGRN; i++) { 163 WRITE4(sc, CCM_CCGR(i), 0xffffffff); 164 } 165 166 /* Enable ENET clocks */ 167 reg = READ4(sc, CCM_CSCDR1); 168 reg |= (ENET_TS_EN | RMII_CLK_EN); 169 WRITE4(sc, CCM_CSCDR1, reg); 170 171 return (0); 172 } 173 174 static device_method_t ccm_methods[] = { 175 DEVMETHOD(device_probe, ccm_probe), 176 DEVMETHOD(device_attach, ccm_attach), 177 { 0, 0 } 178 }; 179 180 static driver_t ccm_driver = { 181 "ccm", 182 ccm_methods, 183 sizeof(struct ccm_softc), 184 }; 185 186 static devclass_t ccm_devclass; 187 188 DRIVER_MODULE(ccm, simplebus, ccm_driver, ccm_devclass, 0, 0); 189