imx51_ccm.c revision 271055
1248557Sray/* $NetBSD: imx51_ccm.c,v 1.1 2012/04/17 09:33:31 bsh Exp $ */ 2248557Sray/* 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: head/sys/arm/freescale/imx/imx51_ccm.c 271055 2014-09-03 21:45:39Z ian $"); 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> 81248557Sray#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 100248557Sraystruct imxccm_softc { 101248557Sray device_t sc_dev; 102248557Sray struct resource *res[7]; 103248557Sray u_int64_t pll_freq[IMX51_N_DPLLS]; 104248557Sray}; 105248557Sray 106248557Sraystruct imxccm_softc *ccm_softc = NULL; 107248557Sray 108248557Sraystatic uint64_t imx51_get_pll_freq(u_int); 109248557Sray 110248557Sraystatic int imxccm_match(device_t); 111248557Sraystatic int imxccm_attach(device_t); 112248557Sray 113248557Sraystatic device_method_t imxccm_methods[] = { 114248557Sray DEVMETHOD(device_probe, imxccm_match), 115248557Sray DEVMETHOD(device_attach, imxccm_attach), 116248557Sray 117248557Sray DEVMETHOD_END 118248557Sray}; 119248557Sray 120248557Sraystatic driver_t imxccm_driver = { 121248557Sray "imxccm", 122248557Sray imxccm_methods, 123248557Sray sizeof(struct imxccm_softc), 124248557Sray}; 125248557Sray 126248557Sraystatic devclass_t imxccm_devclass; 127248557Sray 128248557SrayEARLY_DRIVER_MODULE(imxccm, simplebus, imxccm_driver, imxccm_devclass, 0, 0, 129248557Sray BUS_PASS_CPU); 130248557Sray 131248557Sraystatic struct resource_spec imxccm_spec[] = { 132248557Sray { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Global registers */ 133248557Sray { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* DPLLIP1 */ 134248557Sray { SYS_RES_MEMORY, 2, RF_ACTIVE }, /* DPLLIP2 */ 135248557Sray { SYS_RES_MEMORY, 3, RF_ACTIVE }, /* DPLLIP3 */ 136248557Sray { SYS_RES_IRQ, 0, RF_ACTIVE }, /* 71 */ 137248557Sray { SYS_RES_IRQ, 1, RF_ACTIVE }, /* 72 */ 138248557Sray { -1, 0 } 139248557Sray}; 140248557Sray 141248557Sraystatic int 142248557Srayimxccm_match(device_t dev) 143248557Sray{ 144248557Sray 145261410Sian if (!ofw_bus_status_okay(dev)) 146261410Sian return (ENXIO); 147261410Sian 148255130Srpaulo if (!ofw_bus_is_compatible(dev, "fsl,imx51-ccm") && 149255130Srpaulo !ofw_bus_is_compatible(dev, "fsl,imx53-ccm")) 150248557Sray return (ENXIO); 151248557Sray 152248557Sray device_set_desc(dev, "Freescale Clock Control Module"); 153248557Sray return (BUS_PROBE_DEFAULT); 154248557Sray} 155248557Sray 156248557Sraystatic int 157248557Srayimxccm_attach(device_t dev) 158248557Sray{ 159248557Sray struct imxccm_softc *sc; 160248557Sray 161248557Sray sc = device_get_softc(dev); 162248557Sray sc->sc_dev = dev; 163248557Sray 164248557Sray if (bus_alloc_resources(dev, imxccm_spec, sc->res)) { 165248557Sray device_printf(dev, "could not allocate resources\n"); 166248557Sray return (ENXIO); 167248557Sray } 168248557Sray 169248557Sray ccm_softc = sc; 170248557Sray 171248557Sray imx51_get_pll_freq(1); 172248557Sray imx51_get_pll_freq(2); 173248557Sray imx51_get_pll_freq(3); 174248557Sray 175248557Sray device_printf(dev, "PLL1=%lluMHz, PLL2=%lluMHz, PLL3=%lluMHz\n", 176248557Sray sc->pll_freq[0] / 1000000, 177248557Sray sc->pll_freq[1] / 1000000, 178248557Sray sc->pll_freq[2] / 1000000); 179248557Sray device_printf(dev, "CPU clock=%d, UART clock=%d\n", 180248557Sray imx51_get_clock(IMX51CLK_ARM_ROOT), 181248557Sray imx51_get_clock(IMX51CLK_UART_CLK_ROOT)); 182248557Sray device_printf(dev, 183248557Sray "mainbus clock=%d, ahb clock=%d ipg clock=%d perclk=%d\n", 184248557Sray imx51_get_clock(IMX51CLK_MAIN_BUS_CLK), 185248557Sray imx51_get_clock(IMX51CLK_AHB_CLK_ROOT), 186248557Sray imx51_get_clock(IMX51CLK_IPG_CLK_ROOT), 187248557Sray imx51_get_clock(IMX51CLK_PERCLK_ROOT)); 188248557Sray 189248557Sray 190248557Sray return (0); 191248557Sray} 192248557Sray 193248557Srayu_int 194248557Srayimx51_get_clock(enum imx51_clock clk) 195248557Sray{ 196248557Sray u_int freq; 197248557Sray u_int sel; 198248557Sray uint32_t cacrr; /* ARM clock root register */ 199248557Sray uint32_t ccsr; 200248557Sray uint32_t cscdr1; 201248557Sray uint32_t cscmr1; 202248557Sray uint32_t cbcdr; 203248557Sray uint32_t cbcmr; 204248557Sray uint32_t cdcr; 205248557Sray 206248557Sray if (ccm_softc == NULL) 207248557Sray return (0); 208248557Sray 209248557Sray switch (clk) { 210248557Sray case IMX51CLK_PLL1: 211248557Sray case IMX51CLK_PLL2: 212248557Sray case IMX51CLK_PLL3: 213248557Sray return ccm_softc->pll_freq[clk-IMX51CLK_PLL1]; 214248557Sray case IMX51CLK_PLL1SW: 215248557Sray ccsr = bus_read_4(ccm_softc->res[0], CCMC_CCSR); 216248557Sray if ((ccsr & CCSR_PLL1_SW_CLK_SEL) == 0) 217248557Sray return ccm_softc->pll_freq[1-1]; 218248557Sray /* step clock */ 219248557Sray /* FALLTHROUGH */ 220248557Sray case IMX51CLK_PLL1STEP: 221248557Sray ccsr = bus_read_4(ccm_softc->res[0], CCMC_CCSR); 222248557Sray switch ((ccsr & CCSR_STEP_SEL_MASK) >> CCSR_STEP_SEL_SHIFT) { 223248557Sray case 0: 224248557Sray return imx51_get_clock(IMX51CLK_LP_APM); 225248557Sray case 1: 226248557Sray return 0; /* XXX PLL bypass clock */ 227248557Sray case 2: 228248557Sray return ccm_softc->pll_freq[2-1] / 229248557Sray (1 + ((ccsr & CCSR_PLL2_DIV_PODF_MASK) >> 230248557Sray CCSR_PLL2_DIV_PODF_SHIFT)); 231248557Sray case 3: 232248557Sray return ccm_softc->pll_freq[3-1] / 233248557Sray (1 + ((ccsr & CCSR_PLL3_DIV_PODF_MASK) >> 234248557Sray CCSR_PLL3_DIV_PODF_SHIFT)); 235248557Sray } 236248557Sray /*NOTREACHED*/ 237248557Sray case IMX51CLK_PLL2SW: 238248557Sray ccsr = bus_read_4(ccm_softc->res[0], CCMC_CCSR); 239248557Sray if ((ccsr & CCSR_PLL2_SW_CLK_SEL) == 0) 240248557Sray return imx51_get_clock(IMX51CLK_PLL2); 241248557Sray return 0; /* XXX PLL2 bypass clk */ 242248557Sray case IMX51CLK_PLL3SW: 243248557Sray ccsr = bus_read_4(ccm_softc->res[0], CCMC_CCSR); 244248557Sray if ((ccsr & CCSR_PLL3_SW_CLK_SEL) == 0) 245248557Sray return imx51_get_clock(IMX51CLK_PLL3); 246248557Sray return 0; /* XXX PLL3 bypass clk */ 247248557Sray 248248557Sray case IMX51CLK_LP_APM: 249248557Sray ccsr = bus_read_4(ccm_softc->res[0], CCMC_CCSR); 250248557Sray return (ccsr & CCSR_LP_APM) ? 251248557Sray imx51_get_clock(IMX51CLK_FPM) : IMX51_OSC_FREQ; 252248557Sray 253248557Sray case IMX51CLK_ARM_ROOT: 254248557Sray freq = imx51_get_clock(IMX51CLK_PLL1SW); 255248557Sray cacrr = bus_read_4(ccm_softc->res[0], CCMC_CACRR); 256248557Sray return freq / (cacrr + 1); 257248557Sray 258248557Sray /* ... */ 259248557Sray case IMX51CLK_MAIN_BUS_CLK_SRC: 260248557Sray cbcdr = bus_read_4(ccm_softc->res[0], CCMC_CBCDR); 261248557Sray if ((cbcdr & CBCDR_PERIPH_CLK_SEL) == 0) 262248557Sray freq = imx51_get_clock(IMX51CLK_PLL2SW); 263248557Sray else { 264248557Sray freq = 0; 265248557Sray cbcmr = bus_read_4(ccm_softc->res[0], CCMC_CBCMR); 266248557Sray switch ((cbcmr & CBCMR_PERIPH_APM_SEL_MASK) >> 267248557Sray CBCMR_PERIPH_APM_SEL_SHIFT) { 268248557Sray case 0: 269248557Sray freq = imx51_get_clock(IMX51CLK_PLL1SW); 270248557Sray break; 271248557Sray case 1: 272248557Sray freq = imx51_get_clock(IMX51CLK_PLL3SW); 273248557Sray break; 274248557Sray case 2: 275248557Sray freq = imx51_get_clock(IMX51CLK_LP_APM); 276248557Sray break; 277248557Sray case 3: 278248557Sray /* XXX: error */ 279248557Sray break; 280248557Sray } 281248557Sray } 282248557Sray return freq; 283248557Sray case IMX51CLK_MAIN_BUS_CLK: 284248557Sray freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK_SRC); 285248557Sray cdcr = bus_read_4(ccm_softc->res[0], CCMC_CDCR); 286256774Sian return freq / (1 + ((cdcr & CDCR_PERIPH_CLK_DVFS_PODF_MASK) >> 287256774Sian CDCR_PERIPH_CLK_DVFS_PODF_SHIFT)); 288248557Sray case IMX51CLK_AHB_CLK_ROOT: 289248557Sray freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK); 290248557Sray cbcdr = bus_read_4(ccm_softc->res[0], CCMC_CBCDR); 291248557Sray return freq / (1 + ((cbcdr & CBCDR_AHB_PODF_MASK) >> 292248557Sray CBCDR_AHB_PODF_SHIFT)); 293248557Sray case IMX51CLK_IPG_CLK_ROOT: 294248557Sray freq = imx51_get_clock(IMX51CLK_AHB_CLK_ROOT); 295248557Sray cbcdr = bus_read_4(ccm_softc->res[0], CCMC_CBCDR); 296248557Sray return freq / (1 + ((cbcdr & CBCDR_IPG_PODF_MASK) >> 297248557Sray CBCDR_IPG_PODF_SHIFT)); 298248557Sray 299248557Sray case IMX51CLK_PERCLK_ROOT: 300248557Sray cbcmr = bus_read_4(ccm_softc->res[0], CCMC_CBCMR); 301248557Sray if (cbcmr & CBCMR_PERCLK_IPG_SEL) 302248557Sray return imx51_get_clock(IMX51CLK_IPG_CLK_ROOT); 303248557Sray if (cbcmr & CBCMR_PERCLK_LP_APM_SEL) 304248557Sray freq = imx51_get_clock(IMX51CLK_LP_APM); 305248557Sray else 306248557Sray freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK_SRC); 307248557Sray cbcdr = bus_read_4(ccm_softc->res[0], CCMC_CBCDR); 308248557Sray 309248557Sray#ifdef IMXCCMDEBUG 310248557Sray printf("cbcmr=%x cbcdr=%x\n", cbcmr, cbcdr); 311248557Sray#endif 312248557Sray 313248557Sray freq /= 1 + ((cbcdr & CBCDR_PERCLK_PRED1_MASK) >> 314248557Sray CBCDR_PERCLK_PRED1_SHIFT); 315248557Sray freq /= 1 + ((cbcdr & CBCDR_PERCLK_PRED2_MASK) >> 316248557Sray CBCDR_PERCLK_PRED2_SHIFT); 317248557Sray freq /= 1 + ((cbcdr & CBCDR_PERCLK_PODF_MASK) >> 318248557Sray CBCDR_PERCLK_PODF_SHIFT); 319248557Sray return freq; 320248557Sray case IMX51CLK_UART_CLK_ROOT: 321248557Sray cscdr1 = bus_read_4(ccm_softc->res[0], CCMC_CSCDR1); 322248557Sray cscmr1 = bus_read_4(ccm_softc->res[0], CCMC_CSCMR1); 323248557Sray 324248557Sray#ifdef IMXCCMDEBUG 325248557Sray printf("cscdr1=%x cscmr1=%x\n", cscdr1, cscmr1); 326248557Sray#endif 327248557Sray 328248557Sray sel = (cscmr1 & CSCMR1_UART_CLK_SEL_MASK) >> 329248557Sray CSCMR1_UART_CLK_SEL_SHIFT; 330248557Sray 331248557Sray freq = 0; /* shut up GCC */ 332248557Sray switch (sel) { 333248557Sray case 0: 334248557Sray case 1: 335248557Sray case 2: 336248557Sray freq = imx51_get_clock(IMX51CLK_PLL1SW + sel); 337248557Sray break; 338248557Sray case 3: 339248557Sray freq = imx51_get_clock(IMX51CLK_LP_APM); 340248557Sray break; 341248557Sray } 342248557Sray 343248557Sray return freq / (1 + ((cscdr1 & CSCDR1_UART_CLK_PRED_MASK) >> 344248557Sray CSCDR1_UART_CLK_PRED_SHIFT)) / 345248557Sray (1 + ((cscdr1 & CSCDR1_UART_CLK_PODF_MASK) >> 346248557Sray CSCDR1_UART_CLK_PODF_SHIFT)); 347248557Sray case IMX51CLK_IPU_HSP_CLK_ROOT: 348248557Sray freq = 0; 349248557Sray cbcmr = bus_read_4(ccm_softc->res[0], CCMC_CBCMR); 350248557Sray switch ((cbcmr & CBCMR_IPU_HSP_CLK_SEL_MASK) >> 351248557Sray CBCMR_IPU_HSP_CLK_SEL_SHIFT) { 352248557Sray case 0: 353248557Sray freq = imx51_get_clock(IMX51CLK_ARM_AXI_A_CLK); 354248557Sray break; 355248557Sray case 1: 356248557Sray freq = imx51_get_clock(IMX51CLK_ARM_AXI_B_CLK); 357248557Sray break; 358248557Sray case 2: 359248557Sray freq = imx51_get_clock( 360248557Sray IMX51CLK_EMI_SLOW_CLK_ROOT); 361248557Sray break; 362248557Sray case 3: 363248557Sray freq = imx51_get_clock(IMX51CLK_AHB_CLK_ROOT); 364248557Sray break; 365248557Sray } 366248557Sray return freq; 367248557Sray default: 368248557Sray device_printf(ccm_softc->sc_dev, 369248557Sray "clock %d: not supported yet\n", clk); 370248557Sray return 0; 371248557Sray } 372248557Sray} 373248557Sray 374248557Sray 375248557Sraystatic uint64_t 376248557Srayimx51_get_pll_freq(u_int pll_no) 377248557Sray{ 378248557Sray uint32_t dp_ctrl; 379248557Sray uint32_t dp_op; 380248557Sray uint32_t dp_mfd; 381248557Sray uint32_t dp_mfn; 382248557Sray uint32_t mfi; 383248557Sray int32_t mfn; 384248557Sray uint32_t mfd; 385248557Sray uint32_t pdf; 386248557Sray uint32_t ccr; 387248557Sray uint64_t freq = 0; 388248557Sray u_int ref = 0; 389248557Sray 390248557Sray KASSERT(1 <= pll_no && pll_no <= IMX51_N_DPLLS, ("Wrong PLL id")); 391248557Sray 392248557Sray dp_ctrl = bus_read_4(ccm_softc->res[pll_no], DPLL_DP_CTL); 393248557Sray 394248557Sray if (dp_ctrl & DP_CTL_HFSM) { 395248557Sray dp_op = bus_read_4(ccm_softc->res[pll_no], DPLL_DP_HFS_OP); 396248557Sray dp_mfd = bus_read_4(ccm_softc->res[pll_no], DPLL_DP_HFS_MFD); 397248557Sray dp_mfn = bus_read_4(ccm_softc->res[pll_no], DPLL_DP_HFS_MFN); 398248557Sray } else { 399248557Sray dp_op = bus_read_4(ccm_softc->res[pll_no], DPLL_DP_OP); 400248557Sray dp_mfd = bus_read_4(ccm_softc->res[pll_no], DPLL_DP_MFD); 401248557Sray dp_mfn = bus_read_4(ccm_softc->res[pll_no], DPLL_DP_MFN); 402248557Sray } 403248557Sray 404248557Sray pdf = dp_op & DP_OP_PDF_MASK; 405248557Sray mfi = max(5, (dp_op & DP_OP_MFI_MASK) >> DP_OP_MFI_SHIFT); 406248557Sray mfd = dp_mfd; 407248557Sray if (dp_mfn & 0x04000000) 408248557Sray /* 27bit signed value */ 409248557Sray mfn = (uint32_t)(0xf8000000 | dp_mfn); 410248557Sray else 411248557Sray mfn = dp_mfn; 412248557Sray 413248557Sray switch (dp_ctrl & DP_CTL_REF_CLK_SEL_MASK) { 414248557Sray case DP_CTL_REF_CLK_SEL_COSC: 415248557Sray /* Internal Oscillator */ 416248557Sray /* TODO: get from FDT "fsl,imx-osc" */ 417248557Sray ref = 24000000; /* IMX51_OSC_FREQ */ 418248557Sray break; 419248557Sray case DP_CTL_REF_CLK_SEL_FPM: 420248557Sray ccr = bus_read_4(ccm_softc->res[0], CCMC_CCR); 421248557Sray if (ccr & CCR_FPM_MULT) 422248557Sray /* TODO: get from FDT "fsl,imx-ckil" */ 423248557Sray ref = 32768 * 1024; 424248557Sray else 425248557Sray /* TODO: get from FDT "fsl,imx-ckil" */ 426248557Sray ref = 32768 * 512; 427248557Sray break; 428248557Sray default: 429248557Sray ref = 0; 430248557Sray } 431248557Sray 432248557Sray if (dp_ctrl & DP_CTL_REF_CLK_DIV) 433248557Sray ref /= 2; 434248557Sray 435248557Sray ref *= 4; 436248557Sray freq = (int64_t)ref * mfi + (int64_t)ref * mfn / (mfd + 1); 437248557Sray freq /= pdf + 1; 438248557Sray 439248557Sray if (!(dp_ctrl & DP_CTL_DPDCK0_2_EN)) 440248557Sray freq /= 2; 441248557Sray 442248557Sray#ifdef IMXCCMDEBUG 443248557Sray printf("ref: %dKHz ", ref); 444248557Sray printf("dp_ctl: %08x ", dp_ctrl); 445248557Sray printf("pdf: %3d ", pdf); 446248557Sray printf("mfi: %3d ", mfi); 447248557Sray printf("mfd: %3d ", mfd); 448248557Sray printf("mfn: %3d ", mfn); 449248557Sray printf("pll: %d\n", (uint32_t)freq); 450248557Sray#endif 451248557Sray 452248557Sray ccm_softc->pll_freq[pll_no-1] = freq; 453248557Sray 454248557Sray return (freq); 455248557Sray} 456248557Sray 457248557Srayvoid 458248557Srayimx51_clk_gating(int clk_src, int mode) 459248557Sray{ 460248557Sray int field, group; 461248557Sray uint32_t reg; 462248557Sray 463248557Sray group = CCMR_CCGR_MODULE(clk_src); 464248557Sray field = clk_src % CCMR_CCGR_NSOURCE; 465248557Sray reg = bus_read_4(ccm_softc->res[0], CCMC_CCGR(group)); 466248557Sray reg &= ~(0x03 << field * 2); 467248557Sray reg |= (mode << field * 2); 468248557Sray bus_write_4(ccm_softc->res[0], CCMC_CCGR(group), reg); 469248557Sray} 470248557Sray 471248557Srayint 472248557Srayimx51_get_clk_gating(int clk_src) 473248557Sray{ 474248557Sray uint32_t reg; 475248557Sray 476248557Sray reg = bus_read_4(ccm_softc->res[0], 477248557Sray CCMC_CCGR(CCMR_CCGR_MODULE(clk_src))); 478248557Sray return ((reg >> (clk_src % CCMR_CCGR_NSOURCE) * 2) & 0x03); 479248557Sray} 480248557Sray 481257383Sian/* 482257383Sian * Code from here down is temporary, in lieu of a SoC-independent clock API. 483257383Sian */ 484257383Sian 485257383Sianvoid 486257383Sianimx_ccm_usb_enable(device_t dev) 487257383Sian{ 488257383Sian uint32_t regval; 489257383Sian 490257383Sian /* 491257383Sian * Select PLL2 as the source for the USB clock. 492257383Sian * The default is PLL3, but U-boot changes it to PLL2. 493257383Sian */ 494257383Sian regval = bus_read_4(ccm_softc->res[0], CCMC_CSCMR1); 495257383Sian regval &= ~CSCMR1_USBOH3_CLK_SEL_MASK; 496257383Sian regval |= 1 << CSCMR1_USBOH3_CLK_SEL_SHIFT; 497257383Sian bus_write_4(ccm_softc->res[0], CCMC_CSCMR1, regval); 498257383Sian 499257383Sian /* 500257383Sian * Set the USB clock pre-divider to div-by-5, post-divider to div-by-2. 501257383Sian */ 502257383Sian regval = bus_read_4(ccm_softc->res[0], CCMC_CSCDR1); 503257383Sian regval &= ~CSCDR1_USBOH3_CLK_PODF_MASK; 504257383Sian regval &= ~CSCDR1_USBOH3_CLK_PRED_MASK; 505257383Sian regval |= 4 << CSCDR1_USBOH3_CLK_PRED_SHIFT; 506257383Sian regval |= 1 << CSCDR1_USBOH3_CLK_PODF_SHIFT; 507257383Sian bus_write_4(ccm_softc->res[0], CCMC_CSCDR1, regval); 508257383Sian 509257383Sian /* 510257383Sian * The same two clocks gates are used on imx51 and imx53. 511257383Sian */ 512257383Sian imx51_clk_gating(CCGR_USBOH3_IPG_AHB_CLK, CCGR_CLK_MODE_ALWAYS); 513257383Sian imx51_clk_gating(CCGR_USBOH3_60M_CLK, CCGR_CLK_MODE_ALWAYS); 514257383Sian} 515257383Sian 516257383Sianvoid 517257383Sianimx_ccm_usbphy_enable(device_t dev) 518257383Sian{ 519257383Sian uint32_t regval; 520257383Sian 521257383Sian /* 522257383Sian * Select PLL3 as the source for the USBPHY clock. U-boot does this 523257383Sian * only for imx53, but the bit exists on imx51. That seems a bit 524257383Sian * strange, but we'll go with it until more is known. 525257383Sian */ 526257383Sian if (imx_soc_type() == IMXSOC_53) { 527257383Sian regval = bus_read_4(ccm_softc->res[0], CCMC_CSCMR1); 528257383Sian regval |= 1 << CSCMR1_USBPHY_CLK_SEL_SHIFT; 529257383Sian bus_write_4(ccm_softc->res[0], CCMC_CSCMR1, regval); 530257383Sian } 531257383Sian 532257383Sian /* 533257383Sian * For the imx51 there's just one phy gate control, enable it. 534257383Sian */ 535257383Sian if (imx_soc_type() == IMXSOC_51) { 536257383Sian imx51_clk_gating(CCGR_USB_PHY_CLK, CCGR_CLK_MODE_ALWAYS); 537257383Sian return; 538257383Sian } 539257383Sian 540257383Sian /* 541257383Sian * For imx53 we don't have a full set of clock defines yet, but the 542257383Sian * datasheet says: 543257383Sian * gate reg 4, bits 13-12 usb ph2 clock (usb_phy2_clk_enable) 544257383Sian * gate reg 4, bits 11-10 usb ph1 clock (usb_phy1_clk_enable) 545257383Sian * 546257383Sian * We should use the fdt data for the device to figure out which of 547257383Sian * the two we're working on, but for now just turn them both on. 548257383Sian */ 549257383Sian if (imx_soc_type() == IMXSOC_53) { 550257383Sian imx51_clk_gating(__CCGR_NUM(4, 5), CCGR_CLK_MODE_ALWAYS); 551257383Sian imx51_clk_gating(__CCGR_NUM(4, 6), CCGR_CLK_MODE_ALWAYS); 552257383Sian return; 553257383Sian } 554257383Sian} 555257383Sian 556264977Sianuint32_t 557264977Sianimx_ccm_ipg_hz(void) 558264977Sian{ 559264977Sian 560264977Sian return (imx51_get_clock(IMX51CLK_IPG_CLK_ROOT)); 561264977Sian} 562264977Sian 563264977Sianuint32_t 564264977Sianimx_ccm_sdhci_hz(void) 565264977Sian{ 566264977Sian 567264977Sian return (imx51_get_clock(IMX51CLK_ESDHC1_CLK_ROOT)); 568264977Sian} 569264977Sian 570264977Sianuint32_t 571264977Sianimx_ccm_perclk_hz(void) 572264977Sian{ 573264977Sian 574264977Sian return (imx51_get_clock(IMX51CLK_PERCLK_ROOT)); 575264977Sian} 576264977Sian 577264977Sianuint32_t 578264977Sianimx_ccm_uart_hz(void) 579264977Sian{ 580264977Sian 581264977Sian return (imx51_get_clock(IMX51CLK_UART_CLK_ROOT)); 582264977Sian} 583271055Sian 584271055Sianuint32_t 585271055Sianimx_ccm_ahb_hz(void) 586271055Sian{ 587271055Sian 588271055Sian return (imx51_get_clock(IMX51CLK_AHB_CLK_ROOT)); 589271055Sian} 590