1 /*- 2 * Copyright (c) 2011 Semihalf. 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 * From: FreeBSD: src/sys/arm/mv/kirkwood/sheevaplug.c,v 1.2 2010/06/13 13:28:53 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/bus.h> 35 36 #include <machine/bus.h> 37 #include <machine/armreg.h> 38 39 #include <arm/mv/mvreg.h> 40 #include <arm/mv/mvvar.h> 41 42 #include <dev/fdt/fdt_common.h> 43 #include <dev/ofw/openfirm.h> 44 45 #include <machine/fdt.h> 46 47 #define CPU_FREQ_FIELD(sar) (((0x01 & (sar >> 52)) << 3) | \ 48 (0x07 & (sar >> 21))) 49 #define FAB_FREQ_FIELD(sar) (((0x01 & (sar >> 51)) << 4) | \ 50 (0x0F & (sar >> 24))) 51 52 static uint32_t count_l2clk(void); 53 54 /* XXX Make gpio driver optional and remove it */ 55 struct resource_spec mv_gpio_res[] = { 56 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 57 { SYS_RES_IRQ, 0, RF_ACTIVE }, 58 { -1, 0 } 59 }; 60 61 struct vco_freq_ratio { 62 uint8_t vco_cpu; /* VCO to CLK0(CPU) clock ratio */ 63 uint8_t vco_l2c; /* VCO to NB(L2 cache) clock ratio */ 64 uint8_t vco_hcl; /* VCO to HCLK(DDR controller) clock ratio */ 65 uint8_t vco_ddr; /* VCO to DR(DDR memory) clock ratio */ 66 }; 67 68 static struct vco_freq_ratio freq_conf_table[] = { 69 /*00*/ { 1, 1, 4, 2 }, 70 /*01*/ { 1, 2, 2, 2 }, 71 /*02*/ { 2, 2, 6, 3 }, 72 /*03*/ { 2, 2, 3, 3 }, 73 /*04*/ { 1, 2, 3, 3 }, 74 /*05*/ { 1, 2, 4, 2 }, 75 /*06*/ { 1, 1, 2, 2 }, 76 /*07*/ { 2, 3, 6, 6 }, 77 /*08*/ { 2, 3, 5, 5 }, 78 /*09*/ { 1, 2, 6, 3 }, 79 /*10*/ { 2, 4, 10, 5 }, 80 /*11*/ { 1, 3, 6, 6 }, 81 /*12*/ { 1, 2, 5, 5 }, 82 /*13*/ { 1, 3, 6, 3 }, 83 /*14*/ { 1, 2, 5, 5 }, 84 /*15*/ { 2, 2, 5, 5 }, 85 /*16*/ { 1, 1, 3, 3 }, 86 /*17*/ { 2, 5, 10, 10 }, 87 /*18*/ { 1, 3, 8, 4 }, 88 /*19*/ { 1, 1, 2, 1 }, 89 /*20*/ { 2, 3, 6, 3 }, 90 /*21*/ { 1, 2, 8, 4 }, 91 /*22*/ { 2, 5, 10, 5 } 92 }; 93 94 static uint16_t cpu_clock_table[] = { 95 1000, 1066, 1200, 1333, 1500, 1666, 1800, 2000, 600, 667, 800, 1600, 96 2133, 2200, 2400 }; 97 98 uint32_t 99 get_tclk(void) 100 { 101 uint32_t cputype; 102 103 cputype = cpufunc_id(); 104 cputype &= CPU_ID_CPU_MASK; 105 106 if (cputype == CPU_ID_MV88SV584X_V7) 107 return (TCLK_250MHZ); 108 else 109 return (TCLK_200MHZ); 110 } 111 112 static uint32_t 113 count_l2clk(void) 114 { 115 uint64_t sar_reg; 116 uint32_t freq_vco, freq_l2clk; 117 uint8_t sar_cpu_freq, sar_fab_freq, array_size; 118 119 /* Get value of the SAR register and process it */ 120 sar_reg = get_sar_value(); 121 sar_cpu_freq = CPU_FREQ_FIELD(sar_reg); 122 sar_fab_freq = FAB_FREQ_FIELD(sar_reg); 123 124 /* Check if CPU frequency field has correct value */ 125 array_size = sizeof(cpu_clock_table) / sizeof(cpu_clock_table[0]); 126 if (sar_cpu_freq >= array_size) 127 panic("Reserved value in cpu frequency configuration field: " 128 "%d", sar_cpu_freq); 129 130 /* Check if fabric frequency field has correct value */ 131 array_size = sizeof(freq_conf_table) / sizeof(freq_conf_table[0]); 132 if (sar_fab_freq >= array_size) 133 panic("Reserved value in fabric frequency configuration field: " 134 "%d", sar_fab_freq); 135 136 /* Get CPU clock frequency */ 137 freq_vco = cpu_clock_table[sar_cpu_freq] * 138 freq_conf_table[sar_fab_freq].vco_cpu; 139 140 /* Get L2CLK clock frequency */ 141 freq_l2clk = freq_vco / freq_conf_table[sar_fab_freq].vco_l2c; 142 143 /* Round L2CLK value to integer MHz */ 144 if (((freq_vco % freq_conf_table[sar_fab_freq].vco_l2c) * 10 / 145 freq_conf_table[sar_fab_freq].vco_l2c) >= 5) 146 freq_l2clk++; 147 148 return (freq_l2clk * 1000000); 149 } 150 151 uint32_t 152 get_l2clk(void) 153 { 154 static uint32_t l2clk_freq = 0; 155 156 /* If get_l2clk is called first time get L2CLK value from register */ 157 if (l2clk_freq == 0) 158 l2clk_freq = count_l2clk(); 159 160 return (l2clk_freq); 161 } 162 163