1 /* $OpenBSD: dfs.c,v 1.3 2014/07/08 13:06:58 deraadt Exp $ */ 2 /* 3 * Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/proc.h> 21 #include <sys/sysctl.h> 22 23 #include <dev/ofw/openfirm.h> 24 25 #include <machine/cpu.h> 26 #include <machine/autoconf.h> 27 #include <macppc/pci/macobio.h> 28 #include <powerpc/hid.h> 29 30 extern int perflevel; 31 32 struct dfs_softc { 33 struct device sc_dev; 34 int sc_voltage; 35 }; 36 37 int dfs_match(struct device *, void *, void *); 38 void dfs_attach(struct device *, struct device *, void *); 39 void dfs_setperf(int); 40 void dfs_scale_frequency(u_int); 41 42 struct cfattach dfs_ca = { 43 sizeof(struct dfs_softc), dfs_match, dfs_attach 44 }; 45 46 struct cfdriver dfs_cd = { 47 NULL, "dfs", DV_DULL 48 }; 49 50 int 51 dfs_match(struct device *parent, void *arg, void *aux) 52 { 53 struct confargs *ca = aux; 54 uint16_t cpu; 55 56 if (strcmp(ca->ca_name, "cpu-vcore-select") != 0) 57 return (0); 58 59 cpu = ppc_mfpvr() >> 16; 60 if (cpu == PPC_CPU_MPC7447A || cpu == PPC_CPU_MPC7448) 61 return (1); 62 63 return (0); 64 } 65 66 void 67 dfs_attach(struct device *parent, struct device *self, void *aux) 68 { 69 struct dfs_softc *sc = (struct dfs_softc *)self; 70 struct confargs *ca = aux; 71 uint32_t hid1, reg; 72 uint16_t cpu; 73 74 /* 75 * On some models the vcore-select offset is relative to 76 * its parent offset and not to the bus base address. 77 */ 78 OF_getprop(OF_parent(ca->ca_node), "reg", ®, sizeof(reg)); 79 if (reg > ca->ca_reg[0]) 80 sc->sc_voltage = reg + ca->ca_reg[0]; 81 else 82 sc->sc_voltage = ca->ca_reg[0]; 83 84 hid1 = ppc_mfhid1(); 85 86 if (hid1 & HID1_DFS4) { 87 ppc_curfreq = ppc_maxfreq / 4; 88 perflevel = 25; 89 } else if (hid1 & HID1_DFS2) { 90 ppc_curfreq = ppc_maxfreq / 2; 91 perflevel = 50; 92 } 93 94 cpu_setperf = dfs_setperf; 95 96 printf(": speeds: %d, %d", ppc_maxfreq, ppc_maxfreq / 2); 97 98 cpu = ppc_mfpvr() >> 16; 99 if (cpu == PPC_CPU_MPC7448) 100 printf(", %d", ppc_maxfreq / 4); 101 printf(" MHz\n"); 102 } 103 104 void 105 dfs_setperf(int perflevel) 106 { 107 struct dfs_softc *sc = dfs_cd.cd_devs[0]; 108 109 if (perflevel > 50) { 110 if (ppc_curfreq != ppc_maxfreq) { 111 macobio_write(sc->sc_voltage, GPIO_DDR_OUTPUT | 1); 112 delay(1000); 113 dfs_scale_frequency(FREQ_FULL); 114 } 115 } else { 116 uint16_t cpu; 117 118 cpu = ppc_mfpvr() >> 16; 119 if (cpu == PPC_CPU_MPC7448 && perflevel <= 25) { 120 if (ppc_curfreq != ppc_maxfreq / 4) { 121 dfs_scale_frequency(FREQ_QUARTER); 122 macobio_write(sc->sc_voltage, 123 GPIO_DDR_OUTPUT | 0); 124 delay(1000); 125 } 126 } else { 127 if (ppc_curfreq != ppc_maxfreq / 2) { 128 dfs_scale_frequency(FREQ_HALF); 129 macobio_write(sc->sc_voltage, 130 GPIO_DDR_OUTPUT | 0); 131 delay(1000); 132 } 133 } 134 } 135 } 136 137 void 138 dfs_scale_frequency(u_int freq_scale) 139 { 140 uint32_t hid1; 141 int s; 142 143 s = splhigh(); 144 hid1 = ppc_mfhid1(); 145 146 hid1 &= ~(HID1_DFS2 | HID1_DFS4); 147 switch (freq_scale) { 148 case FREQ_QUARTER: 149 hid1 |= HID1_DFS4; 150 ppc_curfreq = ppc_maxfreq / 4; 151 break; 152 case FREQ_HALF: 153 hid1 |= HID1_DFS2; 154 ppc_curfreq = ppc_maxfreq / 2; 155 break; 156 case FREQ_FULL: /* FALLTHROUGH */ 157 default: 158 ppc_curfreq = ppc_maxfreq; 159 } 160 161 asm volatile ("sync"); 162 ppc_mthid1(hid1); 163 asm volatile ("sync; isync"); 164 165 splx(s); 166 } 167