1*89ed722cSmpi /* $OpenBSD: dfs.c,v 1.4 2022/03/13 12:33:01 mpi Exp $ */
20541c039Smpi /*
30541c039Smpi * Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org>
40541c039Smpi *
50541c039Smpi * Permission to use, copy, modify, and distribute this software for any
60541c039Smpi * purpose with or without fee is hereby granted, provided that the above
70541c039Smpi * copyright notice and this permission notice appear in all copies.
80541c039Smpi *
90541c039Smpi * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
100541c039Smpi * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
110541c039Smpi * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
120541c039Smpi * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
130541c039Smpi * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
140541c039Smpi * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
150541c039Smpi * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
160541c039Smpi */
170541c039Smpi
180541c039Smpi #include <sys/param.h>
19dc65b433Sderaadt #include <sys/systm.h>
200541c039Smpi #include <sys/proc.h>
210541c039Smpi #include <sys/sysctl.h>
220541c039Smpi
230541c039Smpi #include <dev/ofw/openfirm.h>
240541c039Smpi
250541c039Smpi #include <machine/cpu.h>
260541c039Smpi #include <machine/autoconf.h>
270541c039Smpi #include <macppc/pci/macobio.h>
287d8c831aSmpi #include <powerpc/hid.h>
290541c039Smpi
300541c039Smpi extern int perflevel;
310541c039Smpi
320541c039Smpi struct dfs_softc {
330541c039Smpi struct device sc_dev;
340541c039Smpi int sc_voltage;
350541c039Smpi };
360541c039Smpi
370541c039Smpi int dfs_match(struct device *, void *, void *);
380541c039Smpi void dfs_attach(struct device *, struct device *, void *);
390541c039Smpi void dfs_setperf(int);
400541c039Smpi void dfs_scale_frequency(u_int);
410541c039Smpi
42*89ed722cSmpi const struct cfattach dfs_ca = {
430541c039Smpi sizeof(struct dfs_softc), dfs_match, dfs_attach
440541c039Smpi };
450541c039Smpi
460541c039Smpi struct cfdriver dfs_cd = {
470541c039Smpi NULL, "dfs", DV_DULL
480541c039Smpi };
490541c039Smpi
500541c039Smpi int
dfs_match(struct device * parent,void * arg,void * aux)510541c039Smpi dfs_match(struct device *parent, void *arg, void *aux)
520541c039Smpi {
530541c039Smpi struct confargs *ca = aux;
540541c039Smpi uint16_t cpu;
550541c039Smpi
560541c039Smpi if (strcmp(ca->ca_name, "cpu-vcore-select") != 0)
570541c039Smpi return (0);
580541c039Smpi
590541c039Smpi cpu = ppc_mfpvr() >> 16;
600541c039Smpi if (cpu == PPC_CPU_MPC7447A || cpu == PPC_CPU_MPC7448)
610541c039Smpi return (1);
620541c039Smpi
630541c039Smpi return (0);
640541c039Smpi }
650541c039Smpi
660541c039Smpi void
dfs_attach(struct device * parent,struct device * self,void * aux)670541c039Smpi dfs_attach(struct device *parent, struct device *self, void *aux)
680541c039Smpi {
690541c039Smpi struct dfs_softc *sc = (struct dfs_softc *)self;
700541c039Smpi struct confargs *ca = aux;
710541c039Smpi uint32_t hid1, reg;
720541c039Smpi uint16_t cpu;
730541c039Smpi
740541c039Smpi /*
750541c039Smpi * On some models the vcore-select offset is relative to
760541c039Smpi * its parent offset and not to the bus base address.
770541c039Smpi */
780541c039Smpi OF_getprop(OF_parent(ca->ca_node), "reg", ®, sizeof(reg));
790541c039Smpi if (reg > ca->ca_reg[0])
800541c039Smpi sc->sc_voltage = reg + ca->ca_reg[0];
810541c039Smpi else
820541c039Smpi sc->sc_voltage = ca->ca_reg[0];
830541c039Smpi
840541c039Smpi hid1 = ppc_mfhid1();
850541c039Smpi
867d8c831aSmpi if (hid1 & HID1_DFS4) {
870541c039Smpi ppc_curfreq = ppc_maxfreq / 4;
880541c039Smpi perflevel = 25;
897d8c831aSmpi } else if (hid1 & HID1_DFS2) {
900541c039Smpi ppc_curfreq = ppc_maxfreq / 2;
910541c039Smpi perflevel = 50;
920541c039Smpi }
930541c039Smpi
940541c039Smpi cpu_setperf = dfs_setperf;
950541c039Smpi
960541c039Smpi printf(": speeds: %d, %d", ppc_maxfreq, ppc_maxfreq / 2);
970541c039Smpi
980541c039Smpi cpu = ppc_mfpvr() >> 16;
990541c039Smpi if (cpu == PPC_CPU_MPC7448)
1000541c039Smpi printf(", %d", ppc_maxfreq / 4);
1010541c039Smpi printf(" MHz\n");
1020541c039Smpi }
1030541c039Smpi
1040541c039Smpi void
dfs_setperf(int perflevel)1050541c039Smpi dfs_setperf(int perflevel)
1060541c039Smpi {
1070541c039Smpi struct dfs_softc *sc = dfs_cd.cd_devs[0];
1080541c039Smpi
1090541c039Smpi if (perflevel > 50) {
1100541c039Smpi if (ppc_curfreq != ppc_maxfreq) {
1110541c039Smpi macobio_write(sc->sc_voltage, GPIO_DDR_OUTPUT | 1);
1120541c039Smpi delay(1000);
1130541c039Smpi dfs_scale_frequency(FREQ_FULL);
1140541c039Smpi }
1150541c039Smpi } else {
1160541c039Smpi uint16_t cpu;
1170541c039Smpi
1180541c039Smpi cpu = ppc_mfpvr() >> 16;
1190541c039Smpi if (cpu == PPC_CPU_MPC7448 && perflevel <= 25) {
1200541c039Smpi if (ppc_curfreq != ppc_maxfreq / 4) {
1210541c039Smpi dfs_scale_frequency(FREQ_QUARTER);
1220541c039Smpi macobio_write(sc->sc_voltage,
1230541c039Smpi GPIO_DDR_OUTPUT | 0);
1240541c039Smpi delay(1000);
1250541c039Smpi }
1260541c039Smpi } else {
1270541c039Smpi if (ppc_curfreq != ppc_maxfreq / 2) {
1280541c039Smpi dfs_scale_frequency(FREQ_HALF);
1290541c039Smpi macobio_write(sc->sc_voltage,
1300541c039Smpi GPIO_DDR_OUTPUT | 0);
1310541c039Smpi delay(1000);
1320541c039Smpi }
1330541c039Smpi }
1340541c039Smpi }
1350541c039Smpi }
1360541c039Smpi
1370541c039Smpi void
dfs_scale_frequency(u_int freq_scale)1380541c039Smpi dfs_scale_frequency(u_int freq_scale)
1390541c039Smpi {
1400541c039Smpi uint32_t hid1;
1410541c039Smpi int s;
1420541c039Smpi
1430541c039Smpi s = splhigh();
1440541c039Smpi hid1 = ppc_mfhid1();
1450541c039Smpi
1467d8c831aSmpi hid1 &= ~(HID1_DFS2 | HID1_DFS4);
1470541c039Smpi switch (freq_scale) {
1480541c039Smpi case FREQ_QUARTER:
1497d8c831aSmpi hid1 |= HID1_DFS4;
1500541c039Smpi ppc_curfreq = ppc_maxfreq / 4;
1510541c039Smpi break;
1520541c039Smpi case FREQ_HALF:
1537d8c831aSmpi hid1 |= HID1_DFS2;
1540541c039Smpi ppc_curfreq = ppc_maxfreq / 2;
1550541c039Smpi break;
1560541c039Smpi case FREQ_FULL: /* FALLTHROUGH */
1570541c039Smpi default:
1580541c039Smpi ppc_curfreq = ppc_maxfreq;
1590541c039Smpi }
1600541c039Smpi
1610541c039Smpi asm volatile ("sync");
1620541c039Smpi ppc_mthid1(hid1);
1630541c039Smpi asm volatile ("sync; isync");
1640541c039Smpi
1650541c039Smpi splx(s);
1660541c039Smpi }
167