Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
nv50.c
Go to the documentation of this file.
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 
26 #include "priv.h"
27 
28 static int
29 pwm_info(struct nouveau_therm *therm, int *line, int *ctrl, int *indx)
30 {
31  if (*line == 0x04) {
32  *ctrl = 0x00e100;
33  *line = 4;
34  *indx = 0;
35  } else
36  if (*line == 0x09) {
37  *ctrl = 0x00e100;
38  *line = 9;
39  *indx = 1;
40  } else
41  if (*line == 0x10) {
42  *ctrl = 0x00e28c;
43  *line = 0;
44  *indx = 0;
45  } else {
46  nv_error(therm, "unknown pwm ctrl for gpio %d\n", *line);
47  return -ENODEV;
48  }
49 
50  return 0;
51 }
52 
53 int
54 nv50_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty)
55 {
56  int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id);
57  if (ret)
58  return ret;
59 
60  if (nv_rd32(therm, ctrl) & (1 << line)) {
61  *divs = nv_rd32(therm, 0x00e114 + (id * 8));
62  *duty = nv_rd32(therm, 0x00e118 + (id * 8));
63  return 0;
64  }
65 
66  return -EINVAL;
67 }
68 
69 int
70 nv50_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty)
71 {
72  int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id);
73  if (ret)
74  return ret;
75 
76  nv_mask(therm, ctrl, 0x00010001 << line, 0x00000001 << line);
77  nv_wr32(therm, 0x00e114 + (id * 8), divs);
78  nv_wr32(therm, 0x00e118 + (id * 8), duty | 0x80000000);
79  return 0;
80 }
81 
82 int
84 {
85  int chipset = nv_device(therm)->chipset;
86  int crystal = nv_device(therm)->crystal;
87  int pwm_clock;
88 
89  /* determine the PWM source clock */
90  if (chipset > 0x50 && chipset < 0x94) {
91  u8 pwm_div = nv_rd32(therm, 0x410c);
92  if (nv_rd32(therm, 0xc040) & 0x800000) {
93  /* Use the HOST clock (100 MHz)
94  * Where does this constant(2.4) comes from? */
95  pwm_clock = (100000000 >> pwm_div) * 10 / 24;
96  } else {
97  /* Where does this constant(20) comes from? */
98  pwm_clock = (crystal * 1000) >> pwm_div;
99  pwm_clock /= 20;
100  }
101  } else {
102  pwm_clock = (crystal * 1000) / 20;
103  }
104 
105  return pwm_clock;
106 }
107 
108 int
110 {
111  return nv_rd32(therm, 0x20400);
112 }
113 
114 static int
115 nv50_therm_ctor(struct nouveau_object *parent,
116  struct nouveau_object *engine,
117  struct nouveau_oclass *oclass, void *data, u32 size,
118  struct nouveau_object **pobject)
119 {
120  struct nouveau_therm_priv *priv;
121  struct nouveau_therm *therm;
122  int ret;
123 
124  ret = nouveau_therm_create(parent, engine, oclass, &priv);
125  *pobject = nv_object(priv);
126  therm = (void *) priv;
127  if (ret)
128  return ret;
129 
130  nouveau_therm_ic_ctor(therm);
132  nouveau_therm_fan_ctor(therm);
133 
134  priv->fan.pwm_get = nv50_fan_pwm_get;
135  priv->fan.pwm_set = nv50_fan_pwm_set;
136  priv->fan.pwm_clock = nv50_fan_pwm_clock;
137 
138  therm->temp_get = nv50_temp_get;
144 
145  return 0;
146 }
147 
148 struct nouveau_oclass
150  .handle = NV_SUBDEV(THERM, 0x50),
151  .ofuncs = &(struct nouveau_ofuncs) {
152  .ctor = nv50_therm_ctor,
153  .dtor = _nouveau_therm_dtor,
154  .init = nouveau_therm_init,
155  .fini = nouveau_therm_fini,
156  },
157 };