1 /* $OpenBSD: dfs.c,v 1.1 2011/05/25 07:42:15 mpi 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/proc.h> 20 #include <sys/sysctl.h> 21 22 #include <dev/ofw/openfirm.h> 23 24 #include <machine/cpu.h> 25 #include <machine/autoconf.h> 26 #include <macppc/pci/macobio.h> 27 28 #define DFS2 (1 << 22) /* Divide-by-Two */ 29 #define DFS4 (1 << 23) /* Divide-by-Four (MPC7448 Specific) */ 30 31 extern int perflevel; 32 33 struct dfs_softc { 34 struct device sc_dev; 35 int sc_voltage; 36 }; 37 38 int dfs_match(struct device *, void *, void *); 39 void dfs_attach(struct device *, struct device *, void *); 40 void dfs_setperf(int); 41 void dfs_scale_frequency(u_int); 42 43 struct cfattach dfs_ca = { 44 sizeof(struct dfs_softc), dfs_match, dfs_attach 45 }; 46 47 struct cfdriver dfs_cd = { 48 NULL, "dfs", DV_DULL 49 }; 50 51 int 52 dfs_match(struct device *parent, void *arg, void *aux) 53 { 54 struct confargs *ca = aux; 55 uint16_t cpu; 56 57 if (strcmp(ca->ca_name, "cpu-vcore-select") != 0) 58 return (0); 59 60 cpu = ppc_mfpvr() >> 16; 61 if (cpu == PPC_CPU_MPC7447A || cpu == PPC_CPU_MPC7448) 62 return (1); 63 64 return (0); 65 } 66 67 void 68 dfs_attach(struct device *parent, struct device *self, void *aux) 69 { 70 struct dfs_softc *sc = (struct dfs_softc *)self; 71 struct confargs *ca = aux; 72 uint32_t hid1, reg; 73 uint16_t cpu; 74 75 /* 76 * On some models the vcore-select offset is relative to 77 * its parent offset and not to the bus base address. 78 */ 79 OF_getprop(OF_parent(ca->ca_node), "reg", ®, sizeof(reg)); 80 if (reg > ca->ca_reg[0]) 81 sc->sc_voltage = reg + ca->ca_reg[0]; 82 else 83 sc->sc_voltage = ca->ca_reg[0]; 84 85 hid1 = ppc_mfhid1(); 86 87 if (hid1 & DFS4) { 88 ppc_curfreq = ppc_maxfreq / 4; 89 perflevel = 25; 90 } else if (hid1 & DFS2) { 91 ppc_curfreq = ppc_maxfreq / 2; 92 perflevel = 50; 93 } 94 95 cpu_setperf = dfs_setperf; 96 97 printf(": speeds: %d, %d", ppc_maxfreq, ppc_maxfreq / 2); 98 99 cpu = ppc_mfpvr() >> 16; 100 if (cpu == PPC_CPU_MPC7448) 101 printf(", %d", ppc_maxfreq / 4); 102 printf(" MHz\n"); 103 } 104 105 void 106 dfs_setperf(int perflevel) 107 { 108 struct dfs_softc *sc = dfs_cd.cd_devs[0]; 109 110 if (perflevel > 50) { 111 if (ppc_curfreq != ppc_maxfreq) { 112 macobio_write(sc->sc_voltage, GPIO_DDR_OUTPUT | 1); 113 delay(1000); 114 dfs_scale_frequency(FREQ_FULL); 115 } 116 } else { 117 uint16_t cpu; 118 119 cpu = ppc_mfpvr() >> 16; 120 if (cpu == PPC_CPU_MPC7448 && perflevel <= 25) { 121 if (ppc_curfreq != ppc_maxfreq / 4) { 122 dfs_scale_frequency(FREQ_QUARTER); 123 macobio_write(sc->sc_voltage, 124 GPIO_DDR_OUTPUT | 0); 125 delay(1000); 126 } 127 } else { 128 if (ppc_curfreq != ppc_maxfreq / 2) { 129 dfs_scale_frequency(FREQ_HALF); 130 macobio_write(sc->sc_voltage, 131 GPIO_DDR_OUTPUT | 0); 132 delay(1000); 133 } 134 } 135 } 136 } 137 138 void 139 dfs_scale_frequency(u_int freq_scale) 140 { 141 uint32_t hid1; 142 int s; 143 144 s = splhigh(); 145 hid1 = ppc_mfhid1(); 146 147 hid1 &= ~(DFS2 | DFS4); 148 switch (freq_scale) { 149 case FREQ_QUARTER: 150 hid1 |= DFS4; 151 ppc_curfreq = ppc_maxfreq / 4; 152 break; 153 case FREQ_HALF: 154 hid1 |= DFS2; 155 ppc_curfreq = ppc_maxfreq / 2; 156 break; 157 case FREQ_FULL: /* FALLTHROUGH */ 158 default: 159 ppc_curfreq = ppc_maxfreq; 160 } 161 162 asm volatile ("sync"); 163 ppc_mthid1(hid1); 164 asm volatile ("sync; isync"); 165 166 splx(s); 167 } 168