cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

nv40.c (5698B)


      1/*
      2 * Copyright 2012 Red Hat Inc.
      3 *
      4 * Permission is hereby granted, free of charge, to any person obtaining a
      5 * copy of this software and associated documentation files (the "Software"),
      6 * to deal in the Software without restriction, including without limitation
      7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 * and/or sell copies of the Software, and to permit persons to whom the
      9 * Software is furnished to do so, subject to the following conditions:
     10 *
     11 * The above copyright notice and this permission notice shall be included in
     12 * all copies or substantial portions of the Software.
     13 *
     14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 * OTHER DEALINGS IN THE SOFTWARE.
     21 *
     22 * Authors: Ben Skeggs
     23 * 	    Martin Peres
     24 */
     25#include "priv.h"
     26
     27enum nv40_sensor_style { INVALID_STYLE = -1, OLD_STYLE = 0, NEW_STYLE = 1 };
     28
     29static enum nv40_sensor_style
     30nv40_sensor_style(struct nvkm_therm *therm)
     31{
     32	switch (therm->subdev.device->chipset) {
     33	case 0x43:
     34	case 0x44:
     35	case 0x4a:
     36	case 0x47:
     37		return OLD_STYLE;
     38	case 0x46:
     39	case 0x49:
     40	case 0x4b:
     41	case 0x4e:
     42	case 0x4c:
     43	case 0x67:
     44	case 0x68:
     45	case 0x63:
     46		return NEW_STYLE;
     47	default:
     48		return INVALID_STYLE;
     49	}
     50}
     51
     52static int
     53nv40_sensor_setup(struct nvkm_therm *therm)
     54{
     55	struct nvkm_device *device = therm->subdev.device;
     56	enum nv40_sensor_style style = nv40_sensor_style(therm);
     57
     58	/* enable ADC readout and disable the ALARM threshold */
     59	if (style == NEW_STYLE) {
     60		nvkm_mask(device, 0x15b8, 0x80000000, 0);
     61		nvkm_wr32(device, 0x15b0, 0x80003fff);
     62		mdelay(20); /* wait for the temperature to stabilize */
     63		return nvkm_rd32(device, 0x15b4) & 0x3fff;
     64	} else if (style == OLD_STYLE) {
     65		nvkm_wr32(device, 0x15b0, 0xff);
     66		mdelay(20); /* wait for the temperature to stabilize */
     67		return nvkm_rd32(device, 0x15b4) & 0xff;
     68	} else
     69		return -ENODEV;
     70}
     71
     72static int
     73nv40_temp_get(struct nvkm_therm *therm)
     74{
     75	struct nvkm_device *device = therm->subdev.device;
     76	struct nvbios_therm_sensor *sensor = &therm->bios_sensor;
     77	enum nv40_sensor_style style = nv40_sensor_style(therm);
     78	int core_temp;
     79
     80	if (style == NEW_STYLE) {
     81		nvkm_wr32(device, 0x15b0, 0x80003fff);
     82		core_temp = nvkm_rd32(device, 0x15b4) & 0x3fff;
     83	} else if (style == OLD_STYLE) {
     84		nvkm_wr32(device, 0x15b0, 0xff);
     85		core_temp = nvkm_rd32(device, 0x15b4) & 0xff;
     86	} else
     87		return -ENODEV;
     88
     89	/* if the slope or the offset is unset, do no use the sensor */
     90	if (!sensor->slope_div || !sensor->slope_mult ||
     91	    !sensor->offset_num || !sensor->offset_den)
     92	    return -ENODEV;
     93
     94	core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
     95	core_temp = core_temp + sensor->offset_num / sensor->offset_den;
     96	core_temp = core_temp + sensor->offset_constant - 8;
     97
     98	/* reserve negative temperatures for errors */
     99	if (core_temp < 0)
    100		core_temp = 0;
    101
    102	return core_temp;
    103}
    104
    105static int
    106nv40_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable)
    107{
    108	struct nvkm_subdev *subdev = &therm->subdev;
    109	struct nvkm_device *device = subdev->device;
    110	u32 mask = enable ? 0x80000000 : 0x00000000;
    111	if      (line == 2) nvkm_mask(device, 0x0010f0, 0x80000000, mask);
    112	else if (line == 9) nvkm_mask(device, 0x0015f4, 0x80000000, mask);
    113	else {
    114		nvkm_error(subdev, "unknown pwm ctrl for gpio %d\n", line);
    115		return -ENODEV;
    116	}
    117	return 0;
    118}
    119
    120static int
    121nv40_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty)
    122{
    123	struct nvkm_subdev *subdev = &therm->subdev;
    124	struct nvkm_device *device = subdev->device;
    125	if (line == 2) {
    126		u32 reg = nvkm_rd32(device, 0x0010f0);
    127		if (reg & 0x80000000) {
    128			*duty = (reg & 0x7fff0000) >> 16;
    129			*divs = (reg & 0x00007fff);
    130			return 0;
    131		}
    132	} else
    133	if (line == 9) {
    134		u32 reg = nvkm_rd32(device, 0x0015f4);
    135		if (reg & 0x80000000) {
    136			*divs = nvkm_rd32(device, 0x0015f8);
    137			*duty = (reg & 0x7fffffff);
    138			return 0;
    139		}
    140	} else {
    141		nvkm_error(subdev, "unknown pwm ctrl for gpio %d\n", line);
    142		return -ENODEV;
    143	}
    144
    145	return -EINVAL;
    146}
    147
    148static int
    149nv40_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty)
    150{
    151	struct nvkm_subdev *subdev = &therm->subdev;
    152	struct nvkm_device *device = subdev->device;
    153	if (line == 2) {
    154		nvkm_mask(device, 0x0010f0, 0x7fff7fff, (duty << 16) | divs);
    155	} else
    156	if (line == 9) {
    157		nvkm_wr32(device, 0x0015f8, divs);
    158		nvkm_mask(device, 0x0015f4, 0x7fffffff, duty);
    159	} else {
    160		nvkm_error(subdev, "unknown pwm ctrl for gpio %d\n", line);
    161		return -ENODEV;
    162	}
    163
    164	return 0;
    165}
    166
    167void
    168nv40_therm_intr(struct nvkm_therm *therm)
    169{
    170	struct nvkm_subdev *subdev = &therm->subdev;
    171	struct nvkm_device *device = subdev->device;
    172	uint32_t stat = nvkm_rd32(device, 0x1100);
    173
    174	/* traitement */
    175
    176	/* ack all IRQs */
    177	nvkm_wr32(device, 0x1100, 0x70000);
    178
    179	nvkm_error(subdev, "THERM received an IRQ: stat = %x\n", stat);
    180}
    181
    182static void
    183nv40_therm_init(struct nvkm_therm *therm)
    184{
    185	nv40_sensor_setup(therm);
    186}
    187
    188static const struct nvkm_therm_func
    189nv40_therm = {
    190	.init = nv40_therm_init,
    191	.intr = nv40_therm_intr,
    192	.pwm_ctrl = nv40_fan_pwm_ctrl,
    193	.pwm_get = nv40_fan_pwm_get,
    194	.pwm_set = nv40_fan_pwm_set,
    195	.temp_get = nv40_temp_get,
    196	.program_alarms = nvkm_therm_program_alarms_polling,
    197};
    198
    199int
    200nv40_therm_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
    201	       struct nvkm_therm **ptherm)
    202{
    203	return nvkm_therm_new_(&nv40_therm, device, type, inst, ptherm);
    204}