1 1.8 rin /* $Id: at91pmc.c,v 1.8 2020/02/24 12:38:57 rin Exp $ */ 2 1.8 rin /* $NetBSD: at91pmc.c,v 1.8 2020/02/24 12:38:57 rin Exp $ */ 3 1.2 matt 4 1.2 matt /* 5 1.2 matt * Copyright (c) 2007 Embedtronics Oy 6 1.2 matt * All rights reserved. 7 1.2 matt * 8 1.2 matt * Redistribution and use in source and binary forms, with or without 9 1.2 matt * modification, are permitted provided that the following conditions 10 1.2 matt * are met: 11 1.2 matt * 1. Redistributions of source code must retain the above copyright 12 1.2 matt * notice, this list of conditions and the following disclaimer. 13 1.2 matt * 2. Redistributions in binary form must reproduce the above copyright 14 1.2 matt * notice, this list of conditions and the following disclaimer in the 15 1.2 matt * documentation and/or other materials provided with the distribution. 16 1.2 matt * 17 1.2 matt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 1.2 matt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 1.2 matt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 1.2 matt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 1.2 matt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 1.2 matt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 1.2 matt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 1.2 matt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 1.2 matt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 1.2 matt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 1.2 matt * POSSIBILITY OF SUCH DAMAGE. 28 1.2 matt */ 29 1.2 matt 30 1.2 matt #include <sys/cdefs.h> 31 1.8 rin __KERNEL_RCSID(0, "$NetBSD: at91pmc.c,v 1.8 2020/02/24 12:38:57 rin Exp $"); 32 1.2 matt 33 1.2 matt #include <sys/types.h> 34 1.2 matt #include <sys/param.h> 35 1.2 matt #include <sys/systm.h> 36 1.2 matt #include <sys/kernel.h> 37 1.2 matt #include <sys/time.h> 38 1.2 matt #include <sys/device.h> 39 1.2 matt 40 1.4 dyoung #include <sys/bus.h> 41 1.2 matt #include <machine/intr.h> 42 1.2 matt 43 1.2 matt #include <arm/cpufunc.h> 44 1.2 matt 45 1.2 matt #include <arm/at91/at91reg.h> 46 1.2 matt #include <arm/at91/at91var.h> 47 1.2 matt #include <arm/at91/at91pmcreg.h> 48 1.2 matt #include <arm/at91/at91pmcvar.h> 49 1.2 matt 50 1.2 matt #define SLOW_CLOCK 32768LU 51 1.2 matt 52 1.2 matt void 53 1.2 matt at91pmc_get_clocks(struct at91bus_clocks *clocks) 54 1.2 matt { 55 1.6 skrll uint64_t mclk, pllaclk, pllbclk, pclk, mstclk; 56 1.6 skrll uint32_t reg; 57 1.2 matt 58 1.2 matt if (!((reg = PMCREG(PMC_MOR)) & PMC_MOR_MOSCEN)) 59 1.8 rin panic("%s: main oscillator not enabled (MOR=%#X)", __FUNCTION__, reg); 60 1.2 matt 61 1.2 matt if (!((reg = PMCREG(PMC_MCFR)) & PMC_MCFR_MAINRDY)) 62 1.8 rin panic("%s: main oscillator not ready (MCFR=%#X)", __FUNCTION__, reg); 63 1.2 matt 64 1.2 matt mclk = ((reg & PMC_MCFR_MAINF) * SLOW_CLOCK) / 16U; 65 1.2 matt 66 1.2 matt // try to guess some nice MHz value 67 1.2 matt if (((mclk / 1000) % 1000) >= 990) { 68 1.2 matt mclk += 1000000U - (mclk % 1000000U); 69 1.2 matt } else if (((mclk / 1000) % 1000) <= 10) { 70 1.2 matt mclk -= (mclk % 1000000U); 71 1.2 matt } 72 1.2 matt 73 1.5 aymeric PMCREG(PMC_PLLICPR) = PMC_PLLICPR_ICPPLLA | PMC_PLLICPR_ICPPLLB; 74 1.5 aymeric 75 1.2 matt reg = PMCREG(PMC_PLLAR); pllaclk = 0; 76 1.2 matt if (reg & PMC_PLL_DIV) { 77 1.2 matt pllaclk = mclk * (((reg & PMC_PLL_MUL) >> PMC_PLL_MUL_SHIFT) + 1); 78 1.2 matt pllaclk /= (reg & PMC_PLL_DIV) >> PMC_PLL_DIV_SHIFT; 79 1.2 matt } 80 1.2 matt 81 1.2 matt reg = PMCREG(PMC_PLLBR); pllbclk = 0; 82 1.2 matt if (reg & PMC_PLL_DIV) { 83 1.2 matt pllbclk = mclk * (((reg & PMC_PLL_MUL) >> PMC_PLL_MUL_SHIFT) + 1); 84 1.2 matt pllbclk /= (reg & PMC_PLL_DIV) >> PMC_PLL_DIV_SHIFT; 85 1.2 matt if (reg & PMC_PLLBR_USB_96M) { 86 1.2 matt pllbclk /= 2; 87 1.2 matt } 88 1.2 matt } 89 1.2 matt 90 1.2 matt reg = PMCREG(PMC_MCKR); 91 1.2 matt switch ((reg & PMC_MCKR_CSS)) { 92 1.2 matt case PMC_MCKR_CSS_SLOW_CLK: 93 1.2 matt pclk = SLOW_CLOCK; 94 1.2 matt break; 95 1.2 matt default: 96 1.2 matt case PMC_MCKR_CSS_MAIN_CLK: 97 1.2 matt pclk = mclk; 98 1.2 matt break; 99 1.2 matt case PMC_MCKR_CSS_PLLA: 100 1.2 matt pclk = pllaclk; 101 1.2 matt break; 102 1.2 matt case PMC_MCKR_CSS_PLLB: 103 1.2 matt pclk = pllbclk; 104 1.2 matt break; 105 1.2 matt } 106 1.2 matt pclk >>= (reg & PMC_MCKR_PRES) >> PMC_MCKR_PRES_SHIFT; 107 1.2 matt mstclk = pclk / (((reg & PMC_MCKR_MDIV) >> PMC_MCKR_MDIV_SHIFT) + 1); 108 1.2 matt 109 1.2 matt clocks->slow = SLOW_CLOCK; 110 1.2 matt clocks->main = mclk; 111 1.2 matt clocks->cpu = pclk; 112 1.2 matt clocks->master = mstclk; 113 1.2 matt clocks->plla = pllaclk; 114 1.2 matt clocks->pllb = pllbclk; 115 1.2 matt } 116 1.2 matt 117 1.2 matt 118 1.2 matt #define PID_COUNT 32 119 1.2 matt static int pid_enable_count[PID_COUNT] = {0}; 120 1.2 matt 121 1.2 matt void 122 1.2 matt at91pmc_peripheral_clock(int pid, int enable) 123 1.2 matt { 124 1.2 matt int s; 125 1.2 matt 126 1.2 matt if (pid < 0 || pid >= PID_COUNT) 127 1.2 matt panic("%s: pid %d out of range", __FUNCTION__, pid); 128 1.2 matt 129 1.2 matt s = splhigh(); 130 1.2 matt 131 1.2 matt if (enable) { 132 1.2 matt pid_enable_count[pid]++; 133 1.2 matt PMCREG(PMC_PCER) = (1U << pid); 134 1.2 matt } else { 135 1.2 matt if (--pid_enable_count[pid] < 0) 136 1.2 matt panic("%s: pid %d enable count got negative (%d)", 137 1.2 matt __FUNCTION__, pid, pid_enable_count[pid]); 138 1.2 matt if (pid_enable_count[pid] == 0) 139 1.2 matt PMCREG(PMC_PCDR) = (1U << pid); 140 1.2 matt } 141 1.2 matt 142 1.2 matt splx(s); 143 1.2 matt 144 1.2 matt if (enable) { 145 1.2 matt int c; 146 1.2 matt for (c = 0; c < 10000; c++) { 147 1.2 matt __insn_barrier(); 148 1.2 matt } 149 1.2 matt } 150 1.2 matt } 151