* [lm-sensors] [PATCH 2.6.32-rc3]hwmon:gm965temp for GM/GME965 IGP
@ 2009-10-13 13:46 LuZhihe
0 siblings, 0 replies; only message in thread
From: LuZhihe @ 2009-10-13 13:46 UTC (permalink / raw)
To: lm-sensors
Subject: [PATCH] hwmon:gm965temp add GM/GME965 IGP temperature
report.[Ver0]
Intel GM/GME965 has two on-die thermal sensors. Driver support the graphics
hot spot temperature report.
Chips GM/GME965 is tested, and seems work. While GM45 and more other desktop
chips are not tested, it may be not work for them. So user need to enable
flag "TEST_MORE" to test them.
Thanks to Tobias Hain<tobias.hain@gmx.de> for helped me to test GM965 chip too, to add desktop chips.
Thanks to Mauro Blanco<blancomau@gmail.com> for helped me to test GME965
chip.
MODULE_DEVICE_TABLE calling in this path just for test, I am not quit
sure about it.
This path waiting for your review, please help me to improve it.
Thank you!
Signed-off-by: Lu Zhihe <tombowfly@gmail.com>
---
diff -uprN -X linux-2.6.32-rc3.orig/Documentation/dontdiff linux-2.6.32-rc3.orig/drivers/hwmon/Kconfig linux-2.6.32-rc3/drivers/hwmon/Kconfig
--- linux-2.6.32-rc3.orig/drivers/hwmon/Kconfig 2009-10-10 23:42:13.000000000 +0000
+++ linux-2.6.32-rc3/drivers/hwmon/Kconfig 2009-10-12 22:33:33.000000000 +0000
@@ -372,6 +372,16 @@ config SENSORS_GL520SM
This driver can also be built as a module. If so, the module
will be called gl520sm.
+config SENSORS_GM965TEMP
+ tristate "Intel GM965 temperature sensor"
+ depends on PCI
+ help
+ If you say yes here you get support for GM965 IGP temperatue
+ sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called gm965temp.
+
config SENSORS_CORETEMP
tristate "Intel Core/Core2/Atom temperature sensor"
depends on X86 && EXPERIMENTAL
diff -uprN -X linux-2.6.32-rc3.orig/Documentation/dontdiff linux-2.6.32-rc3.orig/drivers/hwmon/Makefile linux-2.6.32-rc3/drivers/hwmon/Makefile
--- linux-2.6.32-rc3.orig/drivers/hwmon/Makefile 2009-10-10 23:42:06.000000000 +0000
+++ linux-2.6.32-rc3/drivers/hwmon/Makefile 2009-10-12 22:33:33.000000000 +0000
@@ -46,6 +46,7 @@ obj-$(CONFIG_SENSORS_FSCHMD) += fschmd.o
obj-$(CONFIG_SENSORS_G760A) += g760a.o
obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
+obj-$(CONFIG_SENSORS_GM965TEMP) += gm965temp.o
obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o
obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
diff -uprN -X linux-2.6.32-rc3.orig/Documentation/dontdiff linux-2.6.32-rc3.orig/drivers/hwmon/gm965temp.c linux-2.6.32-rc3/drivers/hwmon/gm965temp.c
--- linux-2.6.32-rc3.orig/drivers/hwmon/gm965temp.c 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.32-rc3/drivers/hwmon/gm965temp.c 2009-10-12 22:56:41.000000000 +0000
@@ -0,0 +1,517 @@
+/*
+ * A hwmon driver for the Intel GM/GME965 chipset IGP
+ * temperature sensors
+ *
+ * Copyright (C) 2009 Lu Zhihe <tombowfly at gmail.com>
+ *
+ * Tested and helped improved by:
+ *
+ * Tobias Hain <tobias.hain@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+#define DRVNAME "gm965temp"
+
+#if 0
+#define TEST_MORE /*For test more desktop chipsets*/
+#endif
+#define USE_RTR /*Flag for report method*/
+
+enum { SHOW_TEMP, SHOW_TJMAX, SHOW_TTARGET, SHOW_LABEL } SHOW;
+
+/*Mobile Series Chipsets, read from TR1/RTR1*/
+#define PCI_DEVICE_ID_INTEL_82965GM 0x2a00
+#define PCI_DEVICE_ID_INTEL_82965GME 0x2a10
+#define PCI_DEVICE_ID_INTEL_GM45 0x2a40
+
+#ifdef TEST_MORE
+/*3 Series Chipsets, read from TSTTP.RELT*/
+#define PCI_DEVICE_ID_INTEL_Q35 0x29b0
+#define PCI_DEVICE_ID_INTEL_G33 0x29c0
+#define PCI_DEVICE_ID_INTEL_Q33 0x29d0
+
+/*4 Series Chipsets, read from TSTTP.RELT*/
+#define PCI_DEVICE_ID_INTEL_Q45 0x2e10
+#define PCI_DEVICE_ID_INTEL_G45 0x2e20
+#define PCI_DEVICE_ID_INTEL_G41 0x2e30
+#define PCI_DEVICE_ID_INTEL_B43_BASE 0x2e40
+#define PCI_DEVICE_ID_INTEL_B43_SOFT_SKU 0x2e90
+#endif
+
+#define IS_GM (data->chipset_id = PCI_DEVICE_ID_INTEL_82965GM \
+ || data->chipset_id = PCI_DEVICE_ID_INTEL_82965GME \
+ || data->chipset_id = PCI_DEVICE_ID_INTEL_GM45)
+
+#define GM965_SYSFS_NAME_LEN 16
+
+#define MCHBAR_I965 0x48 /* MCH Memory Mapped Register BAR */
+#define MCHBAR_MASK 0xfffffc000ULL /* bits 35:14 */
+
+static ssize_t show_label(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf);
+
+static ssize_t show_temp(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf);
+struct gm965temp_data {
+ struct device *hwmon_dev;
+ struct mutex update_lock;
+
+ u64 igp_base;
+ unsigned long igp_len;
+ void __iomem *igp_mmio;
+
+ unsigned int temp;
+ unsigned long chipset_id;
+};
+
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ return sprintf(buf, "%s\n", DRVNAME);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, SHOW_TEMP);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL, SHOW_TJMAX);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL,
+ SHOW_TTARGET);
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_label, NULL, SHOW_LABEL);
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static struct attribute *gm965temp_attributes[] = {
+ &sensor_dev_attr_temp1_label.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group gm965temp_group = {
+ .attrs = gm965temp_attributes,
+};
+
+static const struct pci_device_id gm965temp_pci_ids[] = {
+#define ID(x) \
+ { \
+ .class = (PCI_CLASS_BRIDGE_HOST << 8), \
+ .class_mask = ~0, \
+ .vendor = PCI_VENDOR_ID_INTEL, \
+ .device = x, \
+ .subvendor = PCI_ANY_ID, \
+ .subdevice = PCI_ANY_ID, \
+ }
+ ID(PCI_DEVICE_ID_INTEL_82965GM),
+ ID(PCI_DEVICE_ID_INTEL_82965GME),
+ ID(PCI_DEVICE_ID_INTEL_GM45),
+#ifdef TEST_MORE
+ ID(PCI_DEVICE_ID_INTEL_Q35),
+ ID(PCI_DEVICE_ID_INTEL_G33),
+ ID(PCI_DEVICE_ID_INTEL_Q33),
+ ID(PCI_DEVICE_ID_INTEL_Q45),
+ ID(PCI_DEVICE_ID_INTEL_G45),
+ ID(PCI_DEVICE_ID_INTEL_G41),
+ ID(PCI_DEVICE_ID_INTEL_B43_BASE),
+ ID(PCI_DEVICE_ID_INTEL_B43_SOFT_SKU),
+#endif
+ {}
+};
+
+MODULE_DEVICE_TABLE(pci, gm965temp_pci_ids);
+
+static struct platform_device *igp_pdev;
+static struct pci_dev *pcidev;
+static unsigned long devid;
+
+static u8 igp_read_byte(struct gm965temp_data *data, unsigned long offset)
+{
+ return ioread8(data->igp_mmio + offset);
+}
+
+static u16 igp_read_short(struct gm965temp_data *data, unsigned long offset)
+{
+ return ioread16(data->igp_mmio + offset);
+}
+
+static u32 igp_read_int(struct gm965temp_data *data, unsigned long offset)
+{
+ return ioread32(data->igp_mmio + offset);
+}
+
+static void igp_write_short(struct gm965temp_data *data, unsigned long offset,
+ u16 val)
+{
+ iowrite16(val, data->igp_mmio + offset);
+}
+
+static ssize_t show_label(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ return sprintf(buf, "GM965 IGP\n");
+}
+
+
+#define TSC1 0x1001
+#define TSS1 0x1004
+#define TR1 0x1006
+#define TOF1 0x1007
+#define RTR1 0x1008
+
+#define G_TSC1 0xCD8 /*8 bits*/
+#define G_TSS 0xCDA /*8 bits*/
+#define TSTTP 0xCDC /*32 bits*/
+
+#define G_TSE 0x80
+
+#define TSE 0x8000
+#define TMOV (0x01 << 10)
+#define G_TMOV (0x01 << 4)
+
+#define RELT_MASK 0xFF000000 /*bits 31:24*/
+#define HTPS_MASK 0xFF00 /*bits 15:8 */
+#define CTPS_MASK 0xFF /*bits 7:0 */
+
+#define MAX_RETRIES 6
+
+static struct gm965temp_data *gm965temp_update_device(struct device *dev)
+{
+ struct gm965temp_data *data = dev_get_drvdata(dev);
+ unsigned short tsc1_val = 0;
+#ifdef USE_RTR
+ char rtr1_val = 0;
+ unsigned char tof1_val = 0;
+#else
+ unsigned char tr1_val = 0;
+#endif
+ unsigned short tss1_val = 0, tmov = 0;
+ unsigned int tsttp_val = 0, htps_val = 0;
+ char relt_val = 0;
+ unsigned int tsc1 = 0, tss1 = 0, tse = 0;
+ int temp_val = 0;
+ int i = MAX_RETRIES;
+
+ data->temp = 0x0;
+ if (IS_GM) {
+ tsc1 = TSC1;
+ tss1 = TSS1;
+ tse = TSE;
+ tmov = TMOV;
+ } else {
+ tsc1 = G_TSC1;
+ tss1 = G_TSS;
+ tse = G_TSE;
+ tmov = G_TMOV;
+ }
+
+ mutex_lock(&data->update_lock);
+
+ if (IS_GM)
+ tsc1_val = igp_read_short(data, tsc1);
+ else
+ tsc1_val = igp_read_byte(data, tsc1);
+
+ if (!(tsc1_val & tse)) {
+ igp_write_short(data, tsc1, tsc1_val|tse);
+ if (IS_GM)
+ tsc1_val = igp_read_short(data, tsc1);
+ else
+ tsc1_val = igp_read_byte(data, tsc1);
+ } else {
+ if (IS_GM)
+ tss1_val = igp_read_short(data, tss1);
+ else
+ tss1_val = igp_read_byte(data, tss1);
+
+ /* Wait for the thermal sensor read ready */
+ while (!(tss1_val & tmov) && (0 < i--)) {
+ mdelay(1);
+ udelay(600);
+ if (IS_GM)
+ tss1_val = igp_read_short(data, tss1);
+ else
+ tss1_val = igp_read_byte(data, tss1);
+ }
+
+ /* function to map register values to temperatures taken from
+ * p. 358 http://www.intel.com/design/chipsets/datashts/313053.htm
+ */
+ if (tss1_val & tmov) {
+ if (IS_GM) {
+#ifdef USE_RTR
+ rtr1_val = igp_read_byte(data, RTR1);
+ tof1_val = igp_read_byte(data, TOF1);
+ rtr1_val += tof1_val;
+ if ((rtr1_val != 0xFF) && (rtr1_val != 0x0)) {
+ data->temp = (16*rtr1_val*rtr1_val
+ - 11071*rtr1_val + 1610500)/10;
+ }
+#else
+ tr1_val = igp_read_byte(data, TR1);
+ if ((tr1_val != 0xFF) && (tr1_val != 0x0)) {
+ data->temp = (16*tr1_val*tr1_val
+ - 11071*tr1_val + 1610500)/10;
+ }
+#endif
+ } else {
+ tsttp_val = igp_read_int(data, TSTTP);
+ htps_val = (tsttp_val & HTPS_MASK) >> 8;
+ relt_val = (tsttp_val & RELT_MASK) >> 24;
+ temp_val = htps_val + relt_val;
+ data->temp = (16*temp_val*relt_val
+ - 11071*temp_val + 1610500)/10;
+ }
+ }
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
+static ssize_t show_temp(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct gm965temp_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ unsigned int temp = 0;
+
+ if (attr->index = SHOW_TEMP) {
+ data = gm965temp_update_device(dev);
+ temp = data->temp;
+ return sprintf(buf, "%d\n", temp);
+ } else {
+ unsigned int TjMax = 110;
+ return sprintf(buf, "%d\n", TjMax*1000);
+ }
+}
+
+static int __devinit gm965temp_hwmon_init(struct platform_device *pdev)
+{
+ int res = 0;
+ struct gm965temp_data *data = platform_get_drvdata(pdev);
+
+ res = device_create_file(&pdev->dev, &dev_attr_name);
+ if (res)
+ goto exit_remove;
+
+ res = sysfs_create_group(&pdev->dev.kobj, &gm965temp_group);
+ if (res)
+ goto exit_dev;
+
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ res = PTR_ERR(data->hwmon_dev);
+ goto exit_remove;
+ }
+
+ return res;
+
+exit_remove:
+ sysfs_remove_group(&pdev->dev.kobj, &gm965temp_group);
+exit_dev:
+ device_remove_file(&pdev->dev, &dev_attr_name);
+
+ return res;
+}
+
+static int __devinit gm965temp_add(void)
+{
+ int res = -ENODEV;
+
+ /* only ever going to be one of these */
+ igp_pdev = platform_device_alloc(DRVNAME, 0);
+ if (!igp_pdev)
+ return -ENOMEM;
+
+ res = platform_device_add(igp_pdev);
+ if (res)
+ goto err;
+ return 0;
+
+err:
+ platform_device_put(igp_pdev);
+ return res;
+}
+
+static int __devinit gm965_find_registers(struct gm965temp_data *data)
+{
+ u32 val32 = 0x0UL;
+ u64 val64 = 0x0ULL;
+ int res = -ENODEV;
+
+ if (pci_read_config_dword(pcidev, MCHBAR_I965, &val32))
+ goto out;
+
+ if (!(val32 & 1))
+ pci_write_config_dword(pcidev, MCHBAR_I965, val32 | 1);
+
+ val64 = (u64)val32;
+ if (pci_read_config_dword(pcidev, MCHBAR_I965 + 4, &val32))
+ goto out;
+
+ val64 |= (u64)val32 << 32;
+ data->igp_base = val64 & MCHBAR_MASK;
+ data->igp_len = 16*1024;
+
+ data->chipset_id = devid;
+
+ res = 0;
+out:
+ pci_dev_put(pcidev);
+ return res;
+}
+
+static unsigned long chipset_ids[] = {
+ PCI_DEVICE_ID_INTEL_82965GM,
+ PCI_DEVICE_ID_INTEL_82965GME,
+ PCI_DEVICE_ID_INTEL_GM45,
+#ifdef TEST_MORE
+ PCI_DEVICE_ID_INTEL_Q35,
+ PCI_DEVICE_ID_INTEL_G33,
+ PCI_DEVICE_ID_INTEL_Q33,
+ PCI_DEVICE_ID_INTEL_Q45,
+ PCI_DEVICE_ID_INTEL_G45,
+ PCI_DEVICE_ID_INTEL_G41,
+ PCI_DEVICE_ID_INTEL_B43_BASE,
+ PCI_DEVICE_ID_INTEL_B43_SOFT_SKU,
+#endif
+ 0
+};
+
+static int __devinit gm965temp_probe(struct platform_device *pdev)
+{
+ struct gm965temp_data *data = NULL;
+ struct resource *reso = NULL;
+ int res = -ENODEV;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ res = gm965_find_registers(data);
+ if (res)
+ goto err;
+ /* Set up resource regions */
+ reso = request_mem_region(data->igp_base, data->igp_len, DRVNAME);
+ if (!reso) {
+ printk(KERN_ERR "request_mem_region failed\n");
+ res = -EBUSY;
+ goto err;
+ }
+
+ data->igp_mmio = ioremap_nocache(data->igp_base, data->igp_len);
+ if (!data->igp_mmio) {
+ printk(KERN_ERR "ioremap_nocache failed\n");
+ res = -EBUSY;
+ goto err_map_failed;
+ }
+
+ platform_set_drvdata(pdev, data);
+
+ mutex_init(&data->update_lock);
+
+ res = gm965temp_hwmon_init(pdev);
+ if (res)
+ goto err_init_failed;
+
+ return res;
+
+err_init_failed:
+ iounmap(data->igp_mmio);
+ platform_set_drvdata(pdev, NULL);
+err_map_failed:
+ release_mem_region(data->igp_base, data->igp_len);
+err:
+ kfree(data);
+ return res;
+}
+
+static int __devexit gm965temp_remove(struct platform_device *pdev)
+{
+ struct gm965temp_data *data = platform_get_drvdata(pdev);
+ hwmon_device_unregister(data->hwmon_dev);
+ device_remove_file(&pdev->dev, &dev_attr_name);
+
+ iounmap(data->igp_mmio);
+ release_mem_region(data->igp_base, data->igp_len);
+ platform_set_drvdata(pdev, NULL);
+ kfree(data);
+ return 0;
+}
+
+static struct platform_driver gm965temp_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRVNAME,
+ },
+ .probe = gm965temp_probe,
+ .remove = __devexit_p(gm965temp_remove),
+};
+
+static int __init gm965temp_init(void)
+{
+ int res = 0;
+ unsigned long *i = NULL;
+
+ for (i = chipset_ids; *i != 0; i++) {
+ pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, *i, NULL);
+ if (!pcidev) {
+ printk(KERN_INFO "Try pci_get_device for devid 0x%lx failed\n",
+ *i);
+ pci_dev_put(pcidev);
+ return -ENODEV;
+ } else {
+ devid = *i;
+ break;
+ }
+ }
+
+ res = platform_driver_register(&gm965temp_driver);
+ if (res)
+ return res;
+
+ res = gm965temp_add();
+ if (res)
+ platform_driver_unregister(&gm965temp_driver);
+
+ return res;
+}
+
+static void __exit gm965temp_exit(void)
+{
+ platform_device_unregister(igp_pdev);
+ platform_driver_unregister(&gm965temp_driver);
+}
+
+MODULE_AUTHOR("Lu Zhihe");
+MODULE_DESCRIPTION("Intel GM965 chipset IGP temperature sensor");
+MODULE_LICENSE("GPL and additional rights");
+
+module_init(gm965temp_init);
+module_exit(gm965temp_exit);
+
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2009-10-13 13:46 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-10-13 13:46 [lm-sensors] [PATCH 2.6.32-rc3]hwmon:gm965temp for GM/GME965 IGP LuZhihe
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.