1248557Sray/* $NetBSD: imx51_ccm.c,v 1.1 2012/04/17 09:33:31 bsh Exp $ */ 2331722Seadler/* 3248557Sray * Copyright (c) 2010, 2011, 2012 Genetec Corporation. All rights reserved. 4248557Sray * Written by Hashimoto Kenichi for Genetec Corporation. 5248557Sray * 6248557Sray * Redistribution and use in source and binary forms, with or without 7248557Sray * modification, are permitted provided that the following conditions 8248557Sray * are met: 9248557Sray * 1. Redistributions of source code must retain the above copyright 10248557Sray * notice, this list of conditions and the following disclaimer. 11248557Sray * 2. Redistributions in binary form must reproduce the above copyright 12248557Sray * notice, this list of conditions and the following disclaimer in the 13248557Sray * documentation and/or other materials provided with the distribution. 14248557Sray * 15248557Sray * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND 16248557Sray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17248557Sray * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18248557Sray * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORPORATION 19248557Sray * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20248557Sray * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21248557Sray * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22248557Sray * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23248557Sray * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24248557Sray * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25248557Sray * POSSIBILITY OF SUCH DAMAGE. 26248557Sray */ 27248557Sray 28248557Sray/*- 29250357Sray * Copyright (c) 2012, 2013 The FreeBSD Foundation 30248557Sray * All rights reserved. 31248557Sray * 32248557Sray * Portions of this software were developed by Oleksandr Rybalko 33248557Sray * under sponsorship from the FreeBSD Foundation. 34248557Sray * 35248557Sray * Redistribution and use in source and binary forms, with or without 36248557Sray * modification, are permitted provided that the following conditions 37248557Sray * are met: 38248557Sray * 1. Redistributions of source code must retain the above copyright 39248557Sray * notice, this list of conditions and the following disclaimer. 40248557Sray * 2. Redistributions in binary form must reproduce the above copyright 41248557Sray * notice, this list of conditions and the following disclaimer in the 42248557Sray * documentation and/or other materials provided with the distribution. 43248557Sray * 44248557Sray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 45248557Sray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 46248557Sray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 47248557Sray * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 48248557Sray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 49248557Sray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 50248557Sray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 51248557Sray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 52248557Sray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 53248557Sray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 54248557Sray * SUCH DAMAGE. 55248557Sray */ 56248557Sray 57248557Sray/* 58248557Sray * Clock Controller Module (CCM) 59248557Sray */ 60248557Sray 61248557Sray#include <sys/cdefs.h> 62248557Sray__FBSDID("$FreeBSD: stable/11/sys/arm/freescale/imx/imx51_ccm.c 331722 2018-03-29 02:50:57Z eadler $"); 63248557Sray 64248557Sray#include <sys/param.h> 65248557Sray#include <sys/systm.h> 66248557Sray#include <sys/bus.h> 67248557Sray#include <sys/kernel.h> 68248557Sray#include <sys/module.h> 69248557Sray#include <sys/malloc.h> 70248557Sray#include <sys/rman.h> 71248557Sray#include <machine/bus.h> 72248557Sray#include <machine/cpu.h> 73248557Sray#include <machine/intr.h> 74248557Sray 75248557Sray#include <dev/fdt/fdt_common.h> 76248557Sray#include <dev/ofw/openfirm.h> 77248557Sray#include <dev/ofw/ofw_bus.h> 78248557Sray#include <dev/ofw/ofw_bus_subr.h> 79248557Sray 80248557Sray#include <machine/bus.h> 81323400Sian#include <machine/fdt.h> 82248557Sray 83248557Sray#include <arm/freescale/imx/imx51_ccmvar.h> 84248557Sray#include <arm/freescale/imx/imx51_ccmreg.h> 85248557Sray#include <arm/freescale/imx/imx51_dpllreg.h> 86264977Sian#include <arm/freescale/imx/imx_ccmvar.h> 87257383Sian#include <arm/freescale/imx/imx_machdep.h> 88248557Sray 89248557Sray#define IMXCCMDEBUG 90248557Sray#undef IMXCCMDEBUG 91248557Sray 92248557Sray#ifndef IMX51_OSC_FREQ 93248557Sray#define IMX51_OSC_FREQ (24 * 1000 * 1000) /* 24MHz */ 94248557Sray#endif 95248557Sray 96248557Sray#ifndef IMX51_CKIL_FREQ 97248557Sray#define IMX51_CKIL_FREQ 32768 98248557Sray#endif 99248557Sray 100323400Sian/* 101323400Sian * The fdt data does not provide reg properties describing the DPLL register 102323400Sian * blocks we need to access, presumably because the needed addresses are 103323400Sian * hard-coded within the linux driver. That leaves us with no choice but to do 104323400Sian * the same thing, if we want to run with vendor-supplied fdt data. So here we 105323400Sian * have tables of the physical addresses we need for each soc, and we'll use 106323400Sian * bus_space_map() at attach() time to get access to them. 107323400Sian */ 108323400Sianstatic uint32_t imx51_dpll_addrs[IMX51_N_DPLLS] = { 109323400Sian 0x83f80000, /* DPLL1 */ 110323400Sian 0x83f84000, /* DPLL2 */ 111323400Sian 0x83f88000, /* DPLL3 */ 112323400Sian}; 113323400Sian 114323400Sianstatic uint32_t imx53_dpll_addrs[IMX51_N_DPLLS] = { 115323400Sian 0x63f80000, /* DPLL1 */ 116323400Sian 0x63f84000, /* DPLL2 */ 117323400Sian 0x63f88000, /* DPLL3 */ 118323400Sian}; 119323400Sian 120323400Sian#define DPLL_REGS_SZ (16 * 1024) 121323400Sian 122248557Sraystruct imxccm_softc { 123248557Sray device_t sc_dev; 124323400Sian struct resource *ccmregs; 125248557Sray u_int64_t pll_freq[IMX51_N_DPLLS]; 126323400Sian bus_space_tag_t pllbst; 127323400Sian bus_space_handle_t pllbsh[IMX51_N_DPLLS]; 128248557Sray}; 129248557Sray 130248557Sraystruct imxccm_softc *ccm_softc = NULL; 131248557Sray 132248557Sraystatic uint64_t imx51_get_pll_freq(u_int); 133248557Sray 134248557Sraystatic int imxccm_match(device_t); 135248557Sraystatic int imxccm_attach(device_t); 136248557Sray 137248557Sraystatic device_method_t imxccm_methods[] = { 138248557Sray DEVMETHOD(device_probe, imxccm_match), 139248557Sray DEVMETHOD(device_attach, imxccm_attach), 140248557Sray 141248557Sray DEVMETHOD_END 142248557Sray}; 143248557Sray 144248557Sraystatic driver_t imxccm_driver = { 145248557Sray "imxccm", 146248557Sray imxccm_methods, 147248557Sray sizeof(struct imxccm_softc), 148248557Sray}; 149248557Sray 150248557Sraystatic devclass_t imxccm_devclass; 151248557Sray 152248557SrayEARLY_DRIVER_MODULE(imxccm, simplebus, imxccm_driver, imxccm_devclass, 0, 0, 153248557Sray BUS_PASS_CPU); 154248557Sray 155323400Sianstatic inline uint32_t 156323400Sianpll_read_4(struct imxccm_softc *sc, int pll, int reg) 157323400Sian{ 158248557Sray 159323400Sian return (bus_space_read_4(sc->pllbst, sc->pllbsh[pll - 1], reg)); 160323400Sian} 161323400Sian 162323400Sianstatic inline uint32_t 163323400Sianccm_read_4(struct imxccm_softc *sc, int reg) 164323400Sian{ 165323400Sian 166323400Sian return (bus_read_4(sc->ccmregs, reg)); 167323400Sian} 168323400Sian 169323400Sianstatic inline void 170323400Sianccm_write_4(struct imxccm_softc *sc, int reg, uint32_t val) 171323400Sian{ 172323400Sian 173323400Sian bus_write_4(sc->ccmregs, reg, val); 174323400Sian} 175323400Sian 176248557Sraystatic int 177248557Srayimxccm_match(device_t dev) 178248557Sray{ 179248557Sray 180261410Sian if (!ofw_bus_status_okay(dev)) 181261410Sian return (ENXIO); 182261410Sian 183255130Srpaulo if (!ofw_bus_is_compatible(dev, "fsl,imx51-ccm") && 184255130Srpaulo !ofw_bus_is_compatible(dev, "fsl,imx53-ccm")) 185248557Sray return (ENXIO); 186248557Sray 187248557Sray device_set_desc(dev, "Freescale Clock Control Module"); 188248557Sray return (BUS_PROBE_DEFAULT); 189248557Sray} 190248557Sray 191248557Sraystatic int 192248557Srayimxccm_attach(device_t dev) 193248557Sray{ 194248557Sray struct imxccm_softc *sc; 195323400Sian int idx; 196323400Sian u_int soc; 197323400Sian uint32_t *pll_addrs; 198248557Sray 199248557Sray sc = device_get_softc(dev); 200248557Sray sc->sc_dev = dev; 201248557Sray 202323400Sian switch ((soc = imx_soc_type())) { 203323400Sian case IMXSOC_51: 204323400Sian pll_addrs = imx51_dpll_addrs; 205323400Sian break; 206323400Sian case IMXSOC_53: 207323400Sian pll_addrs = imx53_dpll_addrs; 208323400Sian break; 209323400Sian default: 210323400Sian device_printf(dev, "No support for SoC type 0x%08x\n", soc); 211323400Sian goto noclocks; 212323400Sian } 213323400Sian 214323400Sian idx = 0; 215323400Sian sc->ccmregs = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &idx, 216323400Sian RF_ACTIVE); 217323400Sian if (sc->ccmregs == NULL) { 218248557Sray device_printf(dev, "could not allocate resources\n"); 219323400Sian goto noclocks; 220248557Sray } 221248557Sray 222323400Sian sc->pllbst = fdtbus_bs_tag; 223323400Sian for (idx = 0; idx < IMX51_N_DPLLS; ++idx) { 224323400Sian if (bus_space_map(sc->pllbst, pll_addrs[idx], DPLL_REGS_SZ, 0, 225323400Sian &sc->pllbsh[idx]) != 0) { 226323400Sian device_printf(dev, "Cannot map DPLL registers\n"); 227323400Sian goto noclocks; 228323400Sian } 229323400Sian } 230323400Sian 231248557Sray ccm_softc = sc; 232248557Sray 233248557Sray imx51_get_pll_freq(1); 234248557Sray imx51_get_pll_freq(2); 235248557Sray imx51_get_pll_freq(3); 236248557Sray 237248557Sray device_printf(dev, "PLL1=%lluMHz, PLL2=%lluMHz, PLL3=%lluMHz\n", 238248557Sray sc->pll_freq[0] / 1000000, 239248557Sray sc->pll_freq[1] / 1000000, 240248557Sray sc->pll_freq[2] / 1000000); 241248557Sray device_printf(dev, "CPU clock=%d, UART clock=%d\n", 242248557Sray imx51_get_clock(IMX51CLK_ARM_ROOT), 243248557Sray imx51_get_clock(IMX51CLK_UART_CLK_ROOT)); 244248557Sray device_printf(dev, 245248557Sray "mainbus clock=%d, ahb clock=%d ipg clock=%d perclk=%d\n", 246248557Sray imx51_get_clock(IMX51CLK_MAIN_BUS_CLK), 247248557Sray imx51_get_clock(IMX51CLK_AHB_CLK_ROOT), 248248557Sray imx51_get_clock(IMX51CLK_IPG_CLK_ROOT), 249248557Sray imx51_get_clock(IMX51CLK_PERCLK_ROOT)); 250248557Sray 251248557Sray 252248557Sray return (0); 253323400Sian 254323400Siannoclocks: 255323400Sian 256323400Sian panic("Cannot continue without clock support"); 257248557Sray} 258248557Sray 259248557Srayu_int 260248557Srayimx51_get_clock(enum imx51_clock clk) 261248557Sray{ 262248557Sray u_int freq; 263248557Sray u_int sel; 264248557Sray uint32_t cacrr; /* ARM clock root register */ 265248557Sray uint32_t ccsr; 266248557Sray uint32_t cscdr1; 267248557Sray uint32_t cscmr1; 268248557Sray uint32_t cbcdr; 269248557Sray uint32_t cbcmr; 270248557Sray uint32_t cdcr; 271248557Sray 272248557Sray if (ccm_softc == NULL) 273248557Sray return (0); 274248557Sray 275248557Sray switch (clk) { 276248557Sray case IMX51CLK_PLL1: 277248557Sray case IMX51CLK_PLL2: 278248557Sray case IMX51CLK_PLL3: 279248557Sray return ccm_softc->pll_freq[clk-IMX51CLK_PLL1]; 280248557Sray case IMX51CLK_PLL1SW: 281323400Sian ccsr = ccm_read_4(ccm_softc, CCMC_CCSR); 282248557Sray if ((ccsr & CCSR_PLL1_SW_CLK_SEL) == 0) 283248557Sray return ccm_softc->pll_freq[1-1]; 284248557Sray /* step clock */ 285248557Sray /* FALLTHROUGH */ 286248557Sray case IMX51CLK_PLL1STEP: 287323400Sian ccsr = ccm_read_4(ccm_softc, CCMC_CCSR); 288248557Sray switch ((ccsr & CCSR_STEP_SEL_MASK) >> CCSR_STEP_SEL_SHIFT) { 289248557Sray case 0: 290248557Sray return imx51_get_clock(IMX51CLK_LP_APM); 291248557Sray case 1: 292248557Sray return 0; /* XXX PLL bypass clock */ 293248557Sray case 2: 294248557Sray return ccm_softc->pll_freq[2-1] / 295248557Sray (1 + ((ccsr & CCSR_PLL2_DIV_PODF_MASK) >> 296248557Sray CCSR_PLL2_DIV_PODF_SHIFT)); 297248557Sray case 3: 298248557Sray return ccm_softc->pll_freq[3-1] / 299248557Sray (1 + ((ccsr & CCSR_PLL3_DIV_PODF_MASK) >> 300248557Sray CCSR_PLL3_DIV_PODF_SHIFT)); 301248557Sray } 302248557Sray /*NOTREACHED*/ 303248557Sray case IMX51CLK_PLL2SW: 304323400Sian ccsr = ccm_read_4(ccm_softc, CCMC_CCSR); 305248557Sray if ((ccsr & CCSR_PLL2_SW_CLK_SEL) == 0) 306248557Sray return imx51_get_clock(IMX51CLK_PLL2); 307248557Sray return 0; /* XXX PLL2 bypass clk */ 308248557Sray case IMX51CLK_PLL3SW: 309323400Sian ccsr = ccm_read_4(ccm_softc, CCMC_CCSR); 310248557Sray if ((ccsr & CCSR_PLL3_SW_CLK_SEL) == 0) 311248557Sray return imx51_get_clock(IMX51CLK_PLL3); 312248557Sray return 0; /* XXX PLL3 bypass clk */ 313248557Sray 314248557Sray case IMX51CLK_LP_APM: 315323400Sian ccsr = ccm_read_4(ccm_softc, CCMC_CCSR); 316248557Sray return (ccsr & CCSR_LP_APM) ? 317248557Sray imx51_get_clock(IMX51CLK_FPM) : IMX51_OSC_FREQ; 318248557Sray 319248557Sray case IMX51CLK_ARM_ROOT: 320248557Sray freq = imx51_get_clock(IMX51CLK_PLL1SW); 321323400Sian cacrr = ccm_read_4(ccm_softc, CCMC_CACRR); 322248557Sray return freq / (cacrr + 1); 323248557Sray 324248557Sray /* ... */ 325248557Sray case IMX51CLK_MAIN_BUS_CLK_SRC: 326323400Sian cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR); 327248557Sray if ((cbcdr & CBCDR_PERIPH_CLK_SEL) == 0) 328248557Sray freq = imx51_get_clock(IMX51CLK_PLL2SW); 329248557Sray else { 330248557Sray freq = 0; 331323400Sian cbcmr = ccm_read_4(ccm_softc, CCMC_CBCMR); 332248557Sray switch ((cbcmr & CBCMR_PERIPH_APM_SEL_MASK) >> 333248557Sray CBCMR_PERIPH_APM_SEL_SHIFT) { 334248557Sray case 0: 335248557Sray freq = imx51_get_clock(IMX51CLK_PLL1SW); 336248557Sray break; 337248557Sray case 1: 338248557Sray freq = imx51_get_clock(IMX51CLK_PLL3SW); 339248557Sray break; 340248557Sray case 2: 341248557Sray freq = imx51_get_clock(IMX51CLK_LP_APM); 342248557Sray break; 343248557Sray case 3: 344248557Sray /* XXX: error */ 345248557Sray break; 346248557Sray } 347248557Sray } 348248557Sray return freq; 349248557Sray case IMX51CLK_MAIN_BUS_CLK: 350248557Sray freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK_SRC); 351323400Sian cdcr = ccm_read_4(ccm_softc, CCMC_CDCR); 352256774Sian return freq / (1 + ((cdcr & CDCR_PERIPH_CLK_DVFS_PODF_MASK) >> 353256774Sian CDCR_PERIPH_CLK_DVFS_PODF_SHIFT)); 354248557Sray case IMX51CLK_AHB_CLK_ROOT: 355248557Sray freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK); 356323400Sian cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR); 357248557Sray return freq / (1 + ((cbcdr & CBCDR_AHB_PODF_MASK) >> 358248557Sray CBCDR_AHB_PODF_SHIFT)); 359248557Sray case IMX51CLK_IPG_CLK_ROOT: 360248557Sray freq = imx51_get_clock(IMX51CLK_AHB_CLK_ROOT); 361323400Sian cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR); 362248557Sray return freq / (1 + ((cbcdr & CBCDR_IPG_PODF_MASK) >> 363248557Sray CBCDR_IPG_PODF_SHIFT)); 364248557Sray 365248557Sray case IMX51CLK_PERCLK_ROOT: 366323400Sian cbcmr = ccm_read_4(ccm_softc, CCMC_CBCMR); 367248557Sray if (cbcmr & CBCMR_PERCLK_IPG_SEL) 368248557Sray return imx51_get_clock(IMX51CLK_IPG_CLK_ROOT); 369248557Sray if (cbcmr & CBCMR_PERCLK_LP_APM_SEL) 370248557Sray freq = imx51_get_clock(IMX51CLK_LP_APM); 371248557Sray else 372248557Sray freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK_SRC); 373323400Sian cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR); 374248557Sray 375248557Sray#ifdef IMXCCMDEBUG 376248557Sray printf("cbcmr=%x cbcdr=%x\n", cbcmr, cbcdr); 377248557Sray#endif 378248557Sray 379248557Sray freq /= 1 + ((cbcdr & CBCDR_PERCLK_PRED1_MASK) >> 380248557Sray CBCDR_PERCLK_PRED1_SHIFT); 381248557Sray freq /= 1 + ((cbcdr & CBCDR_PERCLK_PRED2_MASK) >> 382248557Sray CBCDR_PERCLK_PRED2_SHIFT); 383248557Sray freq /= 1 + ((cbcdr & CBCDR_PERCLK_PODF_MASK) >> 384248557Sray CBCDR_PERCLK_PODF_SHIFT); 385248557Sray return freq; 386248557Sray case IMX51CLK_UART_CLK_ROOT: 387323400Sian cscdr1 = ccm_read_4(ccm_softc, CCMC_CSCDR1); 388323400Sian cscmr1 = ccm_read_4(ccm_softc, CCMC_CSCMR1); 389248557Sray 390248557Sray#ifdef IMXCCMDEBUG 391248557Sray printf("cscdr1=%x cscmr1=%x\n", cscdr1, cscmr1); 392248557Sray#endif 393248557Sray 394248557Sray sel = (cscmr1 & CSCMR1_UART_CLK_SEL_MASK) >> 395248557Sray CSCMR1_UART_CLK_SEL_SHIFT; 396248557Sray 397248557Sray freq = 0; /* shut up GCC */ 398248557Sray switch (sel) { 399248557Sray case 0: 400248557Sray case 1: 401248557Sray case 2: 402248557Sray freq = imx51_get_clock(IMX51CLK_PLL1SW + sel); 403248557Sray break; 404248557Sray case 3: 405248557Sray freq = imx51_get_clock(IMX51CLK_LP_APM); 406248557Sray break; 407248557Sray } 408248557Sray 409248557Sray return freq / (1 + ((cscdr1 & CSCDR1_UART_CLK_PRED_MASK) >> 410248557Sray CSCDR1_UART_CLK_PRED_SHIFT)) / 411248557Sray (1 + ((cscdr1 & CSCDR1_UART_CLK_PODF_MASK) >> 412248557Sray CSCDR1_UART_CLK_PODF_SHIFT)); 413248557Sray case IMX51CLK_IPU_HSP_CLK_ROOT: 414248557Sray freq = 0; 415323400Sian cbcmr = ccm_read_4(ccm_softc, CCMC_CBCMR); 416248557Sray switch ((cbcmr & CBCMR_IPU_HSP_CLK_SEL_MASK) >> 417248557Sray CBCMR_IPU_HSP_CLK_SEL_SHIFT) { 418248557Sray case 0: 419248557Sray freq = imx51_get_clock(IMX51CLK_ARM_AXI_A_CLK); 420248557Sray break; 421248557Sray case 1: 422248557Sray freq = imx51_get_clock(IMX51CLK_ARM_AXI_B_CLK); 423248557Sray break; 424248557Sray case 2: 425248557Sray freq = imx51_get_clock( 426248557Sray IMX51CLK_EMI_SLOW_CLK_ROOT); 427248557Sray break; 428248557Sray case 3: 429248557Sray freq = imx51_get_clock(IMX51CLK_AHB_CLK_ROOT); 430248557Sray break; 431248557Sray } 432248557Sray return freq; 433248557Sray default: 434248557Sray device_printf(ccm_softc->sc_dev, 435248557Sray "clock %d: not supported yet\n", clk); 436248557Sray return 0; 437248557Sray } 438248557Sray} 439248557Sray 440248557Sray 441248557Sraystatic uint64_t 442248557Srayimx51_get_pll_freq(u_int pll_no) 443248557Sray{ 444248557Sray uint32_t dp_ctrl; 445248557Sray uint32_t dp_op; 446248557Sray uint32_t dp_mfd; 447248557Sray uint32_t dp_mfn; 448248557Sray uint32_t mfi; 449248557Sray int32_t mfn; 450248557Sray uint32_t mfd; 451248557Sray uint32_t pdf; 452248557Sray uint32_t ccr; 453248557Sray uint64_t freq = 0; 454248557Sray u_int ref = 0; 455248557Sray 456248557Sray KASSERT(1 <= pll_no && pll_no <= IMX51_N_DPLLS, ("Wrong PLL id")); 457248557Sray 458323400Sian dp_ctrl = pll_read_4(ccm_softc, pll_no, DPLL_DP_CTL); 459248557Sray 460248557Sray if (dp_ctrl & DP_CTL_HFSM) { 461323400Sian dp_op = pll_read_4(ccm_softc, pll_no, DPLL_DP_HFS_OP); 462323400Sian dp_mfd = pll_read_4(ccm_softc, pll_no, DPLL_DP_HFS_MFD); 463323400Sian dp_mfn = pll_read_4(ccm_softc, pll_no, DPLL_DP_HFS_MFN); 464248557Sray } else { 465323400Sian dp_op = pll_read_4(ccm_softc, pll_no, DPLL_DP_OP); 466323400Sian dp_mfd = pll_read_4(ccm_softc, pll_no, DPLL_DP_MFD); 467323400Sian dp_mfn = pll_read_4(ccm_softc, pll_no, DPLL_DP_MFN); 468248557Sray } 469248557Sray 470248557Sray pdf = dp_op & DP_OP_PDF_MASK; 471248557Sray mfi = max(5, (dp_op & DP_OP_MFI_MASK) >> DP_OP_MFI_SHIFT); 472248557Sray mfd = dp_mfd; 473248557Sray if (dp_mfn & 0x04000000) 474248557Sray /* 27bit signed value */ 475248557Sray mfn = (uint32_t)(0xf8000000 | dp_mfn); 476248557Sray else 477248557Sray mfn = dp_mfn; 478248557Sray 479248557Sray switch (dp_ctrl & DP_CTL_REF_CLK_SEL_MASK) { 480248557Sray case DP_CTL_REF_CLK_SEL_COSC: 481248557Sray /* Internal Oscillator */ 482248557Sray /* TODO: get from FDT "fsl,imx-osc" */ 483248557Sray ref = 24000000; /* IMX51_OSC_FREQ */ 484248557Sray break; 485248557Sray case DP_CTL_REF_CLK_SEL_FPM: 486323400Sian ccr = ccm_read_4(ccm_softc, CCMC_CCR); 487248557Sray if (ccr & CCR_FPM_MULT) 488248557Sray /* TODO: get from FDT "fsl,imx-ckil" */ 489248557Sray ref = 32768 * 1024; 490248557Sray else 491248557Sray /* TODO: get from FDT "fsl,imx-ckil" */ 492248557Sray ref = 32768 * 512; 493248557Sray break; 494248557Sray default: 495248557Sray ref = 0; 496248557Sray } 497248557Sray 498248557Sray if (dp_ctrl & DP_CTL_REF_CLK_DIV) 499248557Sray ref /= 2; 500248557Sray 501248557Sray ref *= 4; 502248557Sray freq = (int64_t)ref * mfi + (int64_t)ref * mfn / (mfd + 1); 503248557Sray freq /= pdf + 1; 504248557Sray 505248557Sray if (!(dp_ctrl & DP_CTL_DPDCK0_2_EN)) 506248557Sray freq /= 2; 507248557Sray 508248557Sray#ifdef IMXCCMDEBUG 509248557Sray printf("ref: %dKHz ", ref); 510248557Sray printf("dp_ctl: %08x ", dp_ctrl); 511248557Sray printf("pdf: %3d ", pdf); 512248557Sray printf("mfi: %3d ", mfi); 513248557Sray printf("mfd: %3d ", mfd); 514248557Sray printf("mfn: %3d ", mfn); 515248557Sray printf("pll: %d\n", (uint32_t)freq); 516248557Sray#endif 517248557Sray 518248557Sray ccm_softc->pll_freq[pll_no-1] = freq; 519248557Sray 520248557Sray return (freq); 521248557Sray} 522248557Sray 523248557Srayvoid 524248557Srayimx51_clk_gating(int clk_src, int mode) 525248557Sray{ 526248557Sray int field, group; 527248557Sray uint32_t reg; 528248557Sray 529248557Sray group = CCMR_CCGR_MODULE(clk_src); 530248557Sray field = clk_src % CCMR_CCGR_NSOURCE; 531323400Sian reg = ccm_read_4(ccm_softc, CCMC_CCGR(group)); 532248557Sray reg &= ~(0x03 << field * 2); 533248557Sray reg |= (mode << field * 2); 534323400Sian ccm_write_4(ccm_softc, CCMC_CCGR(group), reg); 535248557Sray} 536248557Sray 537248557Srayint 538248557Srayimx51_get_clk_gating(int clk_src) 539248557Sray{ 540248557Sray uint32_t reg; 541248557Sray 542323400Sian reg = ccm_read_4(ccm_softc, 543248557Sray CCMC_CCGR(CCMR_CCGR_MODULE(clk_src))); 544248557Sray return ((reg >> (clk_src % CCMR_CCGR_NSOURCE) * 2) & 0x03); 545248557Sray} 546248557Sray 547257383Sian/* 548257383Sian * Code from here down is temporary, in lieu of a SoC-independent clock API. 549257383Sian */ 550257383Sian 551257383Sianvoid 552257383Sianimx_ccm_usb_enable(device_t dev) 553257383Sian{ 554257383Sian uint32_t regval; 555257383Sian 556257383Sian /* 557257383Sian * Select PLL2 as the source for the USB clock. 558257383Sian * The default is PLL3, but U-boot changes it to PLL2. 559257383Sian */ 560323400Sian regval = ccm_read_4(ccm_softc, CCMC_CSCMR1); 561257383Sian regval &= ~CSCMR1_USBOH3_CLK_SEL_MASK; 562257383Sian regval |= 1 << CSCMR1_USBOH3_CLK_SEL_SHIFT; 563323400Sian ccm_write_4(ccm_softc, CCMC_CSCMR1, regval); 564257383Sian 565257383Sian /* 566257383Sian * Set the USB clock pre-divider to div-by-5, post-divider to div-by-2. 567257383Sian */ 568323400Sian regval = ccm_read_4(ccm_softc, CCMC_CSCDR1); 569257383Sian regval &= ~CSCDR1_USBOH3_CLK_PODF_MASK; 570257383Sian regval &= ~CSCDR1_USBOH3_CLK_PRED_MASK; 571257383Sian regval |= 4 << CSCDR1_USBOH3_CLK_PRED_SHIFT; 572257383Sian regval |= 1 << CSCDR1_USBOH3_CLK_PODF_SHIFT; 573323400Sian ccm_write_4(ccm_softc, CCMC_CSCDR1, regval); 574257383Sian 575257383Sian /* 576257383Sian * The same two clocks gates are used on imx51 and imx53. 577257383Sian */ 578257383Sian imx51_clk_gating(CCGR_USBOH3_IPG_AHB_CLK, CCGR_CLK_MODE_ALWAYS); 579257383Sian imx51_clk_gating(CCGR_USBOH3_60M_CLK, CCGR_CLK_MODE_ALWAYS); 580257383Sian} 581257383Sian 582257383Sianvoid 583257383Sianimx_ccm_usbphy_enable(device_t dev) 584257383Sian{ 585257383Sian uint32_t regval; 586257383Sian 587257383Sian /* 588257383Sian * Select PLL3 as the source for the USBPHY clock. U-boot does this 589257383Sian * only for imx53, but the bit exists on imx51. That seems a bit 590257383Sian * strange, but we'll go with it until more is known. 591257383Sian */ 592257383Sian if (imx_soc_type() == IMXSOC_53) { 593323400Sian regval = ccm_read_4(ccm_softc, CCMC_CSCMR1); 594257383Sian regval |= 1 << CSCMR1_USBPHY_CLK_SEL_SHIFT; 595323400Sian ccm_write_4(ccm_softc, CCMC_CSCMR1, regval); 596257383Sian } 597257383Sian 598257383Sian /* 599257383Sian * For the imx51 there's just one phy gate control, enable it. 600257383Sian */ 601257383Sian if (imx_soc_type() == IMXSOC_51) { 602257383Sian imx51_clk_gating(CCGR_USB_PHY_CLK, CCGR_CLK_MODE_ALWAYS); 603257383Sian return; 604257383Sian } 605257383Sian 606257383Sian /* 607257383Sian * For imx53 we don't have a full set of clock defines yet, but the 608257383Sian * datasheet says: 609257383Sian * gate reg 4, bits 13-12 usb ph2 clock (usb_phy2_clk_enable) 610257383Sian * gate reg 4, bits 11-10 usb ph1 clock (usb_phy1_clk_enable) 611257383Sian * 612257383Sian * We should use the fdt data for the device to figure out which of 613257383Sian * the two we're working on, but for now just turn them both on. 614257383Sian */ 615257383Sian if (imx_soc_type() == IMXSOC_53) { 616257383Sian imx51_clk_gating(__CCGR_NUM(4, 5), CCGR_CLK_MODE_ALWAYS); 617257383Sian imx51_clk_gating(__CCGR_NUM(4, 6), CCGR_CLK_MODE_ALWAYS); 618257383Sian return; 619257383Sian } 620257383Sian} 621257383Sian 622264977Sianuint32_t 623331506Sianimx_ccm_ecspi_hz(void) 624331506Sian{ 625331506Sian 626331506Sian return (imx51_get_clock(IMX51CLK_CSPI_CLK_ROOT)); 627331506Sian} 628331506Sian 629331506Sianuint32_t 630264977Sianimx_ccm_ipg_hz(void) 631264977Sian{ 632264977Sian 633264977Sian return (imx51_get_clock(IMX51CLK_IPG_CLK_ROOT)); 634264977Sian} 635264977Sian 636264977Sianuint32_t 637264977Sianimx_ccm_sdhci_hz(void) 638264977Sian{ 639264977Sian 640264977Sian return (imx51_get_clock(IMX51CLK_ESDHC1_CLK_ROOT)); 641264977Sian} 642264977Sian 643264977Sianuint32_t 644264977Sianimx_ccm_perclk_hz(void) 645264977Sian{ 646264977Sian 647264977Sian return (imx51_get_clock(IMX51CLK_PERCLK_ROOT)); 648264977Sian} 649264977Sian 650264977Sianuint32_t 651264977Sianimx_ccm_uart_hz(void) 652264977Sian{ 653264977Sian 654264977Sian return (imx51_get_clock(IMX51CLK_UART_CLK_ROOT)); 655264977Sian} 656271055Sian 657271055Sianuint32_t 658271055Sianimx_ccm_ahb_hz(void) 659271055Sian{ 660271055Sian 661271055Sian return (imx51_get_clock(IMX51CLK_AHB_CLK_ROOT)); 662271055Sian} 663331506Sian 664