xref: /dflybsd-src/sys/dev/powermng/kate/kate.c (revision 5d302545124b16bb6e9f48d720cba81afba1adb3)
139990074SConstantine A. Murenin /*	$OpenBSD: kate.c,v 1.2 2008/03/27 04:52:03 cnst Exp $	*/
239990074SConstantine A. Murenin 
339990074SConstantine A. Murenin /*
439990074SConstantine A. Murenin  * Copyright (c) 2008/2010 Constantine A. Murenin <cnst+dfly@bugmail.mojo.ru>
539990074SConstantine A. Murenin  *
639990074SConstantine A. Murenin  * Permission to use, copy, modify, and distribute this software for any
739990074SConstantine A. Murenin  * purpose with or without fee is hereby granted, provided that the above
839990074SConstantine A. Murenin  * copyright notice and this permission notice appear in all copies.
939990074SConstantine A. Murenin  *
1039990074SConstantine A. Murenin  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1139990074SConstantine A. Murenin  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1239990074SConstantine A. Murenin  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1339990074SConstantine A. Murenin  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1439990074SConstantine A. Murenin  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1539990074SConstantine A. Murenin  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1639990074SConstantine A. Murenin  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1739990074SConstantine A. Murenin  */
1839990074SConstantine A. Murenin 
1939990074SConstantine A. Murenin #include <sys/param.h>
2039990074SConstantine A. Murenin #include <sys/systm.h>
2139990074SConstantine A. Murenin #include <sys/bus.h>
2239990074SConstantine A. Murenin #include <sys/sensors.h>
2339990074SConstantine A. Murenin 
241d855c79SSascha Wildner #include <machine/specialreg.h>
251d855c79SSascha Wildner 
2639990074SConstantine A. Murenin #include <bus/pci/pcivar.h>
27dcb4b80dSSascha Wildner #include "pcidevs.h"
2839990074SConstantine A. Murenin 
2939990074SConstantine A. Murenin 
3039990074SConstantine A. Murenin /*
3139990074SConstantine A. Murenin  * AMD NPT Family 0Fh Processors, Function 3 -- Miscellaneous Control
3239990074SConstantine A. Murenin  */
3339990074SConstantine A. Murenin 
3439990074SConstantine A. Murenin /* Function 3 Registers */
3539990074SConstantine A. Murenin #define K_THERMTRIP_STAT_R	0xe4
3639990074SConstantine A. Murenin #define K_NORTHBRIDGE_CAP_R	0xe8
3739990074SConstantine A. Murenin #define K_CPUID_FAMILY_MODEL_R	0xfc
3839990074SConstantine A. Murenin 
3939990074SConstantine A. Murenin /* Bits within Thermtrip Status Register */
4039990074SConstantine A. Murenin #define K_THERM_SENSE_SEL	(1 << 6)
4139990074SConstantine A. Murenin #define K_THERM_SENSE_CORE_SEL	(1 << 2)
4239990074SConstantine A. Murenin 
4339990074SConstantine A. Murenin /* Flip core and sensor selection bits */
4439990074SConstantine A. Murenin #define K_T_SEL_C0(v)		(v |= K_THERM_SENSE_CORE_SEL)
4539990074SConstantine A. Murenin #define K_T_SEL_C1(v)		(v &= ~(K_THERM_SENSE_CORE_SEL))
4639990074SConstantine A. Murenin #define K_T_SEL_S0(v)		(v &= ~(K_THERM_SENSE_SEL))
4739990074SConstantine A. Murenin #define K_T_SEL_S1(v)		(v |= K_THERM_SENSE_SEL)
4839990074SConstantine A. Murenin 
4939990074SConstantine A. Murenin 
5039990074SConstantine A. Murenin /*
5139990074SConstantine A. Murenin  * Revision Guide for AMD NPT Family 0Fh Processors,
5239990074SConstantine A. Murenin  * Publication # 33610, Revision 3.30, February 2008
5339990074SConstantine A. Murenin  */
5439990074SConstantine A. Murenin static const struct {
5539990074SConstantine A. Murenin 	const char	rev[5];
5639990074SConstantine A. Murenin 	const uint32_t	cpuid[5];
5739990074SConstantine A. Murenin } kate_proc[] = {
5839990074SConstantine A. Murenin 	{ "BH-F", { 0x00040FB0, 0x00040F80, 0, 0, 0 } },	/* F2 */
5939990074SConstantine A. Murenin 	{ "DH-F", { 0x00040FF0, 0x00050FF0, 0x00040FC0, 0, 0 } }, /* F2, F3 */
6039990074SConstantine A. Murenin 	{ "JH-F", { 0x00040F10, 0x00040F30, 0x000C0F10, 0, 0 } }, /* F2, F3 */
6139990074SConstantine A. Murenin 	{ "BH-G", { 0x00060FB0, 0x00060F80, 0, 0, 0 } },	/* G1, G2 */
6239990074SConstantine A. Murenin 	{ "DH-G", { 0x00070FF0, 0x00060FF0,
6339990074SConstantine A. Murenin 	    0x00060FC0, 0x00070FC0, 0 } }	/* G1, G2 */
6439990074SConstantine A. Murenin };
6539990074SConstantine A. Murenin 
6639990074SConstantine A. Murenin 
6739990074SConstantine A. Murenin struct kate_softc {
68*5d302545SFrançois Tigeot 	device_t		sc_dev;
6939990074SConstantine A. Murenin 
7039990074SConstantine A. Murenin 	struct ksensor		sc_sensors[4];
7139990074SConstantine A. Murenin 	struct ksensordev	sc_sensordev;
7239990074SConstantine A. Murenin 
7339990074SConstantine A. Murenin 	char			sc_rev;
7439990074SConstantine A. Murenin 	int8_t			sc_ii;
7539990074SConstantine A. Murenin 	int8_t			sc_in;
761d855c79SSascha Wildner 	int32_t			sc_flags;
771d855c79SSascha Wildner #define	KATE_FLAG_ALT_OFFSET	0x04	/* CurTmp starts at -28C. */
7839990074SConstantine A. Murenin };
7939990074SConstantine A. Murenin 
80*5d302545SFrançois Tigeot static void	kate_identify(driver_t *, device_t);
81*5d302545SFrançois Tigeot static int	kate_probe(device_t);
82*5d302545SFrançois Tigeot static int	kate_attach(device_t);
83*5d302545SFrançois Tigeot static int	kate_detach(device_t);
8439990074SConstantine A. Murenin static void	kate_refresh(void *);
8539990074SConstantine A. Murenin 
8639990074SConstantine A. Murenin static device_method_t kate_methods[] = {
8739990074SConstantine A. Murenin 	DEVMETHOD(device_identify,	kate_identify),
8839990074SConstantine A. Murenin 	DEVMETHOD(device_probe,		kate_probe),
8939990074SConstantine A. Murenin 	DEVMETHOD(device_attach,	kate_attach),
9039990074SConstantine A. Murenin 	DEVMETHOD(device_detach,	kate_detach),
9139990074SConstantine A. Murenin 	{ NULL, NULL }
9239990074SConstantine A. Murenin };
9339990074SConstantine A. Murenin 
9439990074SConstantine A. Murenin static driver_t kate_driver = {
9539990074SConstantine A. Murenin 	"kate",
9639990074SConstantine A. Murenin 	kate_methods,
9739990074SConstantine A. Murenin 	sizeof(struct kate_softc)
9839990074SConstantine A. Murenin };
9939990074SConstantine A. Murenin 
10039990074SConstantine A. Murenin static devclass_t kate_devclass;
10139990074SConstantine A. Murenin 
10239990074SConstantine A. Murenin DRIVER_MODULE(kate, hostb, kate_driver, kate_devclass, NULL, NULL);
10339990074SConstantine A. Murenin 
10439990074SConstantine A. Murenin 
10539990074SConstantine A. Murenin static void
kate_identify(driver_t * driver,device_t parent)106*5d302545SFrançois Tigeot kate_identify(driver_t *driver, device_t parent)
10739990074SConstantine A. Murenin {
10839990074SConstantine A. Murenin 	if (kate_probe(parent) == ENXIO)
10939990074SConstantine A. Murenin 		return;
11039990074SConstantine A. Murenin 	if (device_find_child(parent, driver->name, -1) != NULL)
11139990074SConstantine A. Murenin 		return;
11239990074SConstantine A. Murenin 	device_add_child(parent, driver->name, -1);
11339990074SConstantine A. Murenin }
11439990074SConstantine A. Murenin 
11539990074SConstantine A. Murenin static int
kate_probe(device_t dev)116*5d302545SFrançois Tigeot kate_probe(device_t dev)
11739990074SConstantine A. Murenin {
11839990074SConstantine A. Murenin #ifndef KATE_STRICT
11939990074SConstantine A. Murenin 	struct kate_softc	ks;
12039990074SConstantine A. Murenin 	struct kate_softc	*sc = &ks;
12139990074SConstantine A. Murenin #endif
12239990074SConstantine A. Murenin 	uint32_t		c;
12339990074SConstantine A. Murenin 	int			i, j;
12439990074SConstantine A. Murenin 
12539990074SConstantine A. Murenin 	if (pci_get_vendor(dev) != PCI_VENDOR_AMD ||
12639990074SConstantine A. Murenin 	    pci_get_device(dev) != PCI_PRODUCT_AMD_AMD64_MISC)
12739990074SConstantine A. Murenin 		return ENXIO;
12839990074SConstantine A. Murenin 
12939990074SConstantine A. Murenin 	/* just in case we probe successfully, set the description */
13039990074SConstantine A. Murenin 	if (device_get_desc(dev) == NULL)
13139990074SConstantine A. Murenin 		device_set_desc(dev,
13239990074SConstantine A. Murenin 		    "AMD Family 0Fh temperature sensors");
13339990074SConstantine A. Murenin 
13439990074SConstantine A. Murenin 	/*
13539990074SConstantine A. Murenin 	 * First, let's probe for chips at or after Revision F, which is
13639990074SConstantine A. Murenin 	 * when the temperature readings were officially introduced.
13739990074SConstantine A. Murenin 	 */
13839990074SConstantine A. Murenin 	c = pci_read_config(dev, K_CPUID_FAMILY_MODEL_R, 4);
139c157ff7aSSascha Wildner 	for (i = 0; i < NELEM(kate_proc); i++)
14039990074SConstantine A. Murenin 		for (j = 0; kate_proc[i].cpuid[j] != 0; j++)
14139990074SConstantine A. Murenin 			if ((c & ~0xf) == kate_proc[i].cpuid[j])
14239990074SConstantine A. Murenin 				return 0;
14339990074SConstantine A. Murenin 
14439990074SConstantine A. Murenin #ifndef KATE_STRICT
14539990074SConstantine A. Murenin 	/*
14639990074SConstantine A. Murenin 	 * If the probe above was not successful, let's try to actually
14739990074SConstantine A. Murenin 	 * read the sensors from the chip, and see if they make any sense.
14839990074SConstantine A. Murenin 	 */
14939990074SConstantine A. Murenin 	sc->sc_ii = 0;
15039990074SConstantine A. Murenin 	sc->sc_in = 4;
15139990074SConstantine A. Murenin 	sc->sc_dev = dev;
15239990074SConstantine A. Murenin 	kate_refresh(sc);
15339990074SConstantine A. Murenin 	for (i = 0; i < 4; i++)
15439990074SConstantine A. Murenin 		if (!(sc->sc_sensors[i].flags & SENSOR_FINVALID))
15539990074SConstantine A. Murenin 			return 0;
15639990074SConstantine A. Murenin #endif /* !KATE_STRICT */
15739990074SConstantine A. Murenin 
15839990074SConstantine A. Murenin 	return ENXIO;
15939990074SConstantine A. Murenin }
16039990074SConstantine A. Murenin 
16139990074SConstantine A. Murenin static int
kate_attach(device_t dev)162*5d302545SFrançois Tigeot kate_attach(device_t dev)
16339990074SConstantine A. Murenin {
16439990074SConstantine A. Murenin 	struct kate_softc	*sc;
16539990074SConstantine A. Murenin 	uint32_t		c, d;
1661d855c79SSascha Wildner 	int			i, j, cmpcap, model;
1671d855c79SSascha Wildner 	u_int			regs[4], brand_id;
16839990074SConstantine A. Murenin 
16939990074SConstantine A. Murenin 	sc = device_get_softc(dev);
17039990074SConstantine A. Murenin 	sc->sc_dev = dev;
17139990074SConstantine A. Murenin 
17239990074SConstantine A. Murenin 	c = pci_read_config(dev, K_CPUID_FAMILY_MODEL_R, 4);
173c157ff7aSSascha Wildner 	for (i = 0; i < NELEM(kate_proc) && sc->sc_rev == '\0'; i++)
17439990074SConstantine A. Murenin 		for (j = 0; kate_proc[i].cpuid[j] != 0; j++)
17539990074SConstantine A. Murenin 			if ((c & ~0xf) == kate_proc[i].cpuid[j]) {
17639990074SConstantine A. Murenin 				sc->sc_rev = kate_proc[i].rev[3];
17781a9d7c8SConstantine A. Murenin 				device_printf(dev, "core rev %.4s%.1x\n",
17839990074SConstantine A. Murenin 				    kate_proc[i].rev, c & 0xf);
17939990074SConstantine A. Murenin 				break;
18039990074SConstantine A. Murenin 			}
18139990074SConstantine A. Murenin 
18239990074SConstantine A. Murenin 	if (c != 0x0 && sc->sc_rev == '\0') {
18339990074SConstantine A. Murenin 		/* CPUID Family Model Register was introduced in Revision F */
18439990074SConstantine A. Murenin 		sc->sc_rev = 'G';	/* newer than E, assume G */
18581a9d7c8SConstantine A. Murenin 		device_printf(dev, "cpuid 0x%x\n", c);
18639990074SConstantine A. Murenin 	}
18739990074SConstantine A. Murenin 
1881d855c79SSascha Wildner 	model = CPUID_TO_MODEL(c);
1891d855c79SSascha Wildner 	if (model >= 0x60 && model != 0xc1) {
1901d855c79SSascha Wildner 		do_cpuid(0x80000001, regs);
1911d855c79SSascha Wildner 		brand_id = (regs[1] >> 9) & 0x1f;
1921d855c79SSascha Wildner 
1931d855c79SSascha Wildner 		switch (model) {
1941d855c79SSascha Wildner 		case 0x68: /* Socket S1g1 */
1951d855c79SSascha Wildner 		case 0x6c:
1961d855c79SSascha Wildner 		case 0x7c:
1971d855c79SSascha Wildner 			break;
1981d855c79SSascha Wildner 		case 0x6b: /* Socket AM2 and ASB1 (2 cores) */
1991d855c79SSascha Wildner 			if (brand_id != 0x0b && brand_id != 0x0c)
2001d855c79SSascha Wildner 				sc->sc_flags |= KATE_FLAG_ALT_OFFSET;
2011d855c79SSascha Wildner 			break;
2021d855c79SSascha Wildner 		case 0x6f: /* Socket AM2 and ASB1 (1 core) */
2031d855c79SSascha Wildner 		case 0x7f:
2041d855c79SSascha Wildner 			if (brand_id != 0x07 && brand_id != 0x09 &&
2051d855c79SSascha Wildner 			    brand_id != 0x0c)
2061d855c79SSascha Wildner 				sc->sc_flags |= KATE_FLAG_ALT_OFFSET;
2071d855c79SSascha Wildner 			break;
2081d855c79SSascha Wildner 		default:
2091d855c79SSascha Wildner 			sc->sc_flags |= KATE_FLAG_ALT_OFFSET;
2101d855c79SSascha Wildner 		}
2111d855c79SSascha Wildner 	}
2121d855c79SSascha Wildner 
21339990074SConstantine A. Murenin 	d = pci_read_config(dev, K_NORTHBRIDGE_CAP_R, 4);
21439990074SConstantine A. Murenin 	cmpcap = (d >> 12) & 0x3;
21539990074SConstantine A. Murenin 
21639990074SConstantine A. Murenin #ifndef KATE_STRICT
21739990074SConstantine A. Murenin 	sc->sc_ii = 0;
21839990074SConstantine A. Murenin 	sc->sc_in = 4;
21939990074SConstantine A. Murenin 	kate_refresh(sc);
22039990074SConstantine A. Murenin 	if (cmpcap == 0) {
22139990074SConstantine A. Murenin 		if ((sc->sc_sensors[0].flags & SENSOR_FINVALID) &&
22239990074SConstantine A. Murenin 		    (sc->sc_sensors[1].flags & SENSOR_FINVALID))
22339990074SConstantine A. Murenin 			sc->sc_ii = 2;
224082d190bSMatthew Dillon 		if ((sc->sc_sensors[3].flags & SENSOR_FINVALID))
22539990074SConstantine A. Murenin 			sc->sc_in = 3;
22639990074SConstantine A. Murenin 	}
22739990074SConstantine A. Murenin #else
22839990074SConstantine A. Murenin 	sc->sc_ii = cmpcap ? 0 : 2;
22939990074SConstantine A. Murenin 	sc->sc_in = 4;
23039990074SConstantine A. Murenin #endif /* !KATE_STRICT */
23139990074SConstantine A. Murenin 
23239990074SConstantine A. Murenin 	strlcpy(sc->sc_sensordev.xname, device_get_nameunit(dev),
23339990074SConstantine A. Murenin 	    sizeof(sc->sc_sensordev.xname));
23439990074SConstantine A. Murenin 
23539990074SConstantine A. Murenin 	for (i = sc->sc_ii; i < sc->sc_in; i++) {
23639990074SConstantine A. Murenin 		sc->sc_sensors[i].type = SENSOR_TEMP;
23739990074SConstantine A. Murenin 		sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
23839990074SConstantine A. Murenin 	}
23939990074SConstantine A. Murenin 
2401bedd63aSSepherosa Ziehau 	sensor_task_register(sc, kate_refresh, 5);
24139990074SConstantine A. Murenin 
24239990074SConstantine A. Murenin 	sensordev_install(&sc->sc_sensordev);
24339990074SConstantine A. Murenin 	return 0;
24439990074SConstantine A. Murenin }
24539990074SConstantine A. Murenin 
24639990074SConstantine A. Murenin static int
kate_detach(device_t dev)247*5d302545SFrançois Tigeot kate_detach(device_t dev)
24839990074SConstantine A. Murenin {
24939990074SConstantine A. Murenin 	struct kate_softc	*sc = device_get_softc(dev);
25039990074SConstantine A. Murenin 
25139990074SConstantine A. Murenin 	sensordev_deinstall(&sc->sc_sensordev);
25239990074SConstantine A. Murenin 	sensor_task_unregister(sc);
25339990074SConstantine A. Murenin 	return 0;
25439990074SConstantine A. Murenin }
25539990074SConstantine A. Murenin 
2560d4e06bcSSascha Wildner static void
kate_refresh(void * arg)25739990074SConstantine A. Murenin kate_refresh(void *arg)
25839990074SConstantine A. Murenin {
25939990074SConstantine A. Murenin 	struct kate_softc	*sc = arg;
26039990074SConstantine A. Murenin 	struct ksensor		*s = sc->sc_sensors;
26139990074SConstantine A. Murenin 	uint32_t		t, m;
2628674b960SSascha Wildner 	int64_t			temp;
26339990074SConstantine A. Murenin 	int			i, v;
26439990074SConstantine A. Murenin 
26539990074SConstantine A. Murenin 	t = pci_read_config(sc->sc_dev, K_THERMTRIP_STAT_R, 4);
26639990074SConstantine A. Murenin 
26739990074SConstantine A. Murenin 	for (i = sc->sc_ii; i < sc->sc_in; i++) {
26839990074SConstantine A. Murenin 		switch(i) {
26939990074SConstantine A. Murenin 		case 0:
27039990074SConstantine A. Murenin 			K_T_SEL_C0(t);
27139990074SConstantine A. Murenin 			K_T_SEL_S0(t);
27239990074SConstantine A. Murenin 			break;
27339990074SConstantine A. Murenin 		case 1:
27439990074SConstantine A. Murenin 			K_T_SEL_C0(t);
27539990074SConstantine A. Murenin 			K_T_SEL_S1(t);
27639990074SConstantine A. Murenin 			break;
27739990074SConstantine A. Murenin 		case 2:
27839990074SConstantine A. Murenin 			K_T_SEL_C1(t);
27939990074SConstantine A. Murenin 			K_T_SEL_S0(t);
28039990074SConstantine A. Murenin 			break;
28139990074SConstantine A. Murenin 		case 3:
28239990074SConstantine A. Murenin 			K_T_SEL_C1(t);
28339990074SConstantine A. Murenin 			K_T_SEL_S1(t);
28439990074SConstantine A. Murenin 			break;
28539990074SConstantine A. Murenin 		}
28639990074SConstantine A. Murenin 		m = t & (K_THERM_SENSE_CORE_SEL | K_THERM_SENSE_SEL);
28739990074SConstantine A. Murenin 		pci_write_config(sc->sc_dev, K_THERMTRIP_STAT_R, t, 4);
28839990074SConstantine A. Murenin 		t = pci_read_config(sc->sc_dev, K_THERMTRIP_STAT_R, 4);
28939990074SConstantine A. Murenin 		v = 0x3ff & (t >> 14);
29039990074SConstantine A. Murenin #ifdef KATE_STRICT
29139990074SConstantine A. Murenin 		if (sc->sc_rev != 'G')
29239990074SConstantine A. Murenin 			v &= ~0x3;
29339990074SConstantine A. Murenin #endif /* KATE_STRICT */
29439990074SConstantine A. Murenin 		if ((t & (K_THERM_SENSE_CORE_SEL | K_THERM_SENSE_SEL)) == m &&
29539990074SConstantine A. Murenin 		    (v & ~0x3) != 0)
29639990074SConstantine A. Murenin 			s[i].flags &= ~SENSOR_FINVALID;
29739990074SConstantine A. Murenin 		else
29839990074SConstantine A. Murenin 			s[i].flags |= SENSOR_FINVALID;
2998674b960SSascha Wildner 		temp = v * 250000;
3008674b960SSascha Wildner 		temp -= (sc->sc_flags & KATE_FLAG_ALT_OFFSET) != 0 ?
3011d855c79SSascha Wildner 		    28000000 : 49000000;
3028674b960SSascha Wildner 		temp += 273150000;
3038674b960SSascha Wildner 		s[i].value = temp;
30439990074SConstantine A. Murenin 	}
30539990074SConstantine A. Murenin }
306