diff -rc cpufreq.org/powernow.c cpufreq/powernow.c *** cpufreq.org/powernow.c Sun Aug 23 10:58:41 2009 --- cpufreq/powernow.c Sun Aug 23 10:17:57 2009 *************** *** 553,564 **** return (0); } /* * Given a set of pair of fid/vid, and number of performance states, * compute powernow_states via an insertion sort. */ static int ! decode_pst(struct pn_softc *sc, uint8_t *p, int npstates) { int i, j, n; struct powernow_state state; --- 553,672 ---- return (0); } + static int + pn_adj_fidvid(device_t dev, struct pn_softc *sc, int pstate, int *fid, int *vid) + { + int new_fid, new_vid; + int org_freq, new_freq, tmp_freq, org_volts, new_volts; + int adjvcore, adjfreq; + char *adjvcore_str = "adjvcoreX", *adjfreq_str = "adjfreqX"; + int rv = 0, i, volts_diff, freq_diff, mult_max = 0; + + /* Define new VID and volts. */ + adjvcore = 0; + resource_int_value(device_get_name(dev), device_get_unit(dev), + "adjvcore", &adjvcore); + sprintf(adjvcore_str, "adjvcore%d", pstate); + resource_int_value(device_get_name(dev), device_get_unit(dev), + adjvcore_str, &adjvcore); + org_volts = sc->vid_to_volts[*vid]; + new_vid = *vid; + new_volts = org_volts + adjvcore; + volts_diff = 3000; + for (i = 0; i < 32; i++) { + if (new_volts == sc->vid_to_volts[i]) { + new_vid = i; + break; + } + if (volts_diff > abs(new_volts - sc->vid_to_volts[i])) { + volts_diff = abs(new_volts - sc->vid_to_volts[i]); + new_vid = i; + } + } + new_volts = sc-> vid_to_volts[new_vid]; + + /* Define new FID and freq. */ + adjfreq = 0; + resource_int_value(device_get_name(dev), device_get_unit(dev), + "adjfreq", &adjfreq); + sprintf(adjfreq_str, "adjfreq%d", pstate); + resource_int_value(device_get_name(dev), device_get_unit(dev), + adjfreq_str, &adjfreq); + new_fid = *fid; + org_freq = tmp_freq = 0; + switch (sc->pn_type) { + case PN7_TYPE: + org_freq = 100 * pn7_fid_to_mult[*fid] * sc->fsb; + mult_max = sizeof(pn7_fid_to_mult) / sizeof(int); + break; + case PN8_TYPE: + org_freq = 100 * pn8_fid_to_mult[*fid] * sc->fsb; + mult_max = sizeof(pn8_fid_to_mult) / sizeof(int); + break; + } + new_freq = org_freq + adjfreq * 1000; + freq_diff = 10000000; + for (i = 0; i < mult_max; i++) { + switch (sc->pn_type) { + case PN7_TYPE: + tmp_freq = 100 * pn7_fid_to_mult[i] * sc->fsb; + break; + case PN8_TYPE: + tmp_freq = 100 * pn8_fid_to_mult[i] * sc->fsb; + break; + } + if (new_freq == tmp_freq) { + new_fid = i; + break; + } + if (freq_diff > abs(new_freq - tmp_freq)) { + freq_diff = abs(new_freq - tmp_freq); + new_fid = i; + } + } + switch (sc->pn_type) { + case PN7_TYPE: + new_freq = 100 * pn7_fid_to_mult[new_fid] * sc->fsb; + break; + case PN8_TYPE: + new_freq = 100 * pn8_fid_to_mult[new_fid] * sc->fsb; + break; + } + + /* Setup new VID and FID. */ + if (*vid != new_vid || *fid != new_fid) { + /* fid and vid of pstate0 must be now adjusted. */ + if (pstate == 0) + switch (sc->pn_type) { + case PN7_TYPE: + rv = pn7_setfidvid(sc, new_fid, new_vid); + break; + case PN8_TYPE: + rv = pn8_setfidvid(sc, new_fid, new_vid); + break; + } + if (rv) { + device_printf(dev, "FID/VID adjustment error! (Over clock is not allowed.)\n"); + return (rv); + } + + device_printf(dev, "P-state%d: %dMHz->%dMHz, %dmV->%dmV\n", + pstate, org_freq / 1000, new_freq / 1000, + org_volts, new_volts); + if (bootverbose) + device_printf(dev, "P-state%d: fid=0x%02x->0x%02x, vid=0x%02x->0x%02x\n", pstate, *fid, new_fid, *vid, new_vid); + *vid = new_vid; + *fid = new_fid; + } + return (0); + } + /* * Given a set of pair of fid/vid, and number of performance states, * compute powernow_states via an insertion sort. */ static int ! decode_pst(device_t dev, struct pn_softc *sc, uint8_t *p, int npstates) { int i, j, n; struct powernow_state state; *************** *** 573,584 **** --- 681,694 ---- switch (sc->pn_type) { case PN7_TYPE: + pn_adj_fidvid(dev, sc, i, &state.fid, &state.vid); state.freq = 100 * pn7_fid_to_mult[state.fid] * sc->fsb; if ((sc->errata & A0_ERRATA) && (pn7_fid_to_mult[state.fid] % 10) == 5) continue; break; case PN8_TYPE: + pn_adj_fidvid(dev, sc, i, &state.fid, &state.vid); state.freq = 100 * pn8_fid_to_mult[state.fid] * sc->fsb; break; } *************** *** 744,750 **** case PN8_TYPE: break; } ! return (decode_pst(sc, p + sizeof(struct pst_header), sc->powernow_max_states)); } --- 854,860 ---- case PN8_TYPE: break; } ! return (decode_pst(dev, sc, p + sizeof(struct pst_header), sc->powernow_max_states)); } *************** *** 801,811 **** --- 911,923 ---- if ((sc->errata & A0_ERRATA) && (pn7_fid_to_mult[state.fid] % 10) == 5) continue; + pn_adj_fidvid(dev, sc, i, &state.fid, &state.vid); state.freq = 100 * pn7_fid_to_mult[state.fid] * sc->fsb; break; case PN8_TYPE: state.fid = ACPI_PN8_CTRL_TO_FID(ctrl); state.vid = ACPI_PN8_CTRL_TO_VID(ctrl); + pn_adj_fidvid(dev, sc, i, &state.fid, &state.vid); state.freq = 100 * pn8_fid_to_mult[state.fid] * sc->fsb; break; }