]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/base.c
Merge branch 'for-4.8/core' of git://git.kernel.dk/linux-block
[karo-tx-linux.git] / drivers / gpu / drm / nouveau / nvkm / subdev / iccsense / base.c
1 /*
2  * Copyright 2015 Martin Peres
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: Martin Peres
23  */
24 #include "priv.h"
25
26 #include <subdev/bios.h>
27 #include <subdev/bios/extdev.h>
28 #include <subdev/bios/iccsense.h>
29 #include <subdev/i2c.h>
30
31 static bool
32 nvkm_iccsense_validate_device(struct i2c_adapter *i2c, u8 addr,
33                               enum nvbios_extdev_type type)
34 {
35         switch (type) {
36         case NVBIOS_EXTDEV_INA209:
37         case NVBIOS_EXTDEV_INA219:
38                 return nv_rd16i2cr(i2c, addr, 0x0) >= 0;
39         case NVBIOS_EXTDEV_INA3221:
40                 return nv_rd16i2cr(i2c, addr, 0xff) == 0x3220 &&
41                        nv_rd16i2cr(i2c, addr, 0xfe) == 0x5449;
42         default:
43                 return false;
44         }
45 }
46
47 static int
48 nvkm_iccsense_poll_lane(struct i2c_adapter *i2c, u8 addr, u8 shunt_reg,
49                         u8 shunt_shift, u8 bus_reg, u8 bus_shift, u8 shunt,
50                         u16 lsb)
51 {
52         int vshunt = nv_rd16i2cr(i2c, addr, shunt_reg);
53         int vbus = nv_rd16i2cr(i2c, addr, bus_reg);
54
55         if (vshunt < 0 || vbus < 0)
56                 return -EINVAL;
57
58         vshunt >>= shunt_shift;
59         vbus >>= bus_shift;
60
61         return vbus * vshunt * lsb / shunt;
62 }
63
64 static int
65 nvkm_iccsense_ina2x9_read(struct nvkm_iccsense *iccsense,
66                           struct nvkm_iccsense_rail *rail,
67                           u8 shunt_reg, u8 bus_reg)
68 {
69         return nvkm_iccsense_poll_lane(rail->sensor->i2c, rail->sensor->addr,
70                                        shunt_reg, 0, bus_reg, 3, rail->mohm,
71                                        10 * 4);
72 }
73
74 static int
75 nvkm_iccsense_ina209_read(struct nvkm_iccsense *iccsense,
76                           struct nvkm_iccsense_rail *rail)
77 {
78         return nvkm_iccsense_ina2x9_read(iccsense, rail, 3, 4);
79 }
80
81 static int
82 nvkm_iccsense_ina219_read(struct nvkm_iccsense *iccsense,
83                           struct nvkm_iccsense_rail *rail)
84 {
85         return nvkm_iccsense_ina2x9_read(iccsense, rail, 1, 2);
86 }
87
88 static int
89 nvkm_iccsense_ina3221_read(struct nvkm_iccsense *iccsense,
90                            struct nvkm_iccsense_rail *rail)
91 {
92         return nvkm_iccsense_poll_lane(rail->sensor->i2c, rail->sensor->addr,
93                                        1 + (rail->idx * 2), 3,
94                                        2 + (rail->idx * 2), 3, rail->mohm,
95                                        40 * 8);
96 }
97
98 static void
99 nvkm_iccsense_ina209_config(struct nvkm_iccsense *iccsense,
100                             struct nvkm_iccsense_sensor *sensor)
101 {
102         struct nvkm_subdev *subdev = &iccsense->subdev;
103         /* configuration:
104          * 0x0007: 0x0007 shunt and bus continous
105          * 0x0078: 0x0078 128 samples shunt
106          * 0x0780: 0x0780 128 samples bus
107          * 0x1800: 0x0000 +-40 mV shunt range
108          * 0x2000: 0x0000 16V FSR
109          */
110         u16 value = 0x07ff;
111         nvkm_debug(subdev, "config for sensor id %i: 0x%x\n", sensor->id, value);
112         nv_wr16i2cr(sensor->i2c, sensor->addr, 0x00, value);
113 }
114
115 static void
116 nvkm_iccsense_ina3221_config(struct nvkm_iccsense *iccsense,
117                              struct nvkm_iccsense_sensor *sensor)
118 {
119         struct nvkm_subdev *subdev = &iccsense->subdev;
120         /* configuration:
121          * 0x0007: 0x0007 shunt and bus continous
122          * 0x0031: 0x0000 140 us conversion time shunt
123          * 0x01c0: 0x0000 140 us conversion time bus
124          * 0x0f00: 0x0f00 1024 samples
125          * 0x7000: 0x?000 channels
126          */
127         u16 value = 0x0e07;
128         if (sensor->rail_mask & 0x1)
129                 value |= 0x1 << 14;
130         if (sensor->rail_mask & 0x2)
131                 value |= 0x1 << 13;
132         if (sensor->rail_mask & 0x4)
133                 value |= 0x1 << 12;
134         nvkm_debug(subdev, "config for sensor id %i: 0x%x\n", sensor->id, value);
135         nv_wr16i2cr(sensor->i2c, sensor->addr, 0x00, value);
136 }
137
138 static void
139 nvkm_iccsense_sensor_config(struct nvkm_iccsense *iccsense,
140                             struct nvkm_iccsense_sensor *sensor)
141 {
142         switch (sensor->type) {
143         case NVBIOS_EXTDEV_INA209:
144         case NVBIOS_EXTDEV_INA219:
145                 nvkm_iccsense_ina209_config(iccsense, sensor);
146                 break;
147         case NVBIOS_EXTDEV_INA3221:
148                 nvkm_iccsense_ina3221_config(iccsense, sensor);
149                 break;
150         default:
151                 break;
152         }
153 }
154
155 int
156 nvkm_iccsense_read_all(struct nvkm_iccsense *iccsense)
157 {
158         int result = 0;
159         struct nvkm_iccsense_rail *rail;
160
161         if (!iccsense)
162                 return -EINVAL;
163
164         list_for_each_entry(rail, &iccsense->rails, head) {
165                 int res;
166                 if (!rail->read)
167                         return -ENODEV;
168
169                 res = rail->read(iccsense, rail);
170                 if (res < 0)
171                         return res;
172                 result += res;
173         }
174         return result;
175 }
176
177 static void *
178 nvkm_iccsense_dtor(struct nvkm_subdev *subdev)
179 {
180         struct nvkm_iccsense *iccsense = nvkm_iccsense(subdev);
181         struct nvkm_iccsense_sensor *sensor, *tmps;
182         struct nvkm_iccsense_rail *rail, *tmpr;
183
184         list_for_each_entry_safe(sensor, tmps, &iccsense->sensors, head) {
185                 list_del(&sensor->head);
186                 kfree(sensor);
187         }
188         list_for_each_entry_safe(rail, tmpr, &iccsense->rails, head) {
189                 list_del(&rail->head);
190                 kfree(rail);
191         }
192
193         return iccsense;
194 }
195
196 static struct nvkm_iccsense_sensor*
197 nvkm_iccsense_create_sensor(struct nvkm_iccsense *iccsense, u8 id)
198 {
199
200         struct nvkm_subdev *subdev = &iccsense->subdev;
201         struct nvkm_bios *bios = subdev->device->bios;
202         struct nvkm_i2c *i2c = subdev->device->i2c;
203         struct nvbios_extdev_func extdev;
204         struct nvkm_i2c_bus *i2c_bus;
205         struct nvkm_iccsense_sensor *sensor;
206         u8 addr;
207
208         if (!i2c || !bios || nvbios_extdev_parse(bios, id, &extdev))
209                 return NULL;
210
211         if (extdev.type == 0xff)
212                 return NULL;
213
214         if (extdev.type != NVBIOS_EXTDEV_INA209 &&
215             extdev.type != NVBIOS_EXTDEV_INA219 &&
216             extdev.type != NVBIOS_EXTDEV_INA3221) {
217                 iccsense->data_valid = false;
218                 nvkm_error(subdev, "Unknown sensor type %x, power reading "
219                            "disabled\n", extdev.type);
220                 return NULL;
221         }
222
223         if (extdev.bus)
224                 i2c_bus = nvkm_i2c_bus_find(i2c, NVKM_I2C_BUS_SEC);
225         else
226                 i2c_bus = nvkm_i2c_bus_find(i2c, NVKM_I2C_BUS_PRI);
227         if (!i2c_bus)
228                 return NULL;
229
230         addr = extdev.addr >> 1;
231         if (!nvkm_iccsense_validate_device(&i2c_bus->i2c, addr,
232                                            extdev.type)) {
233                 iccsense->data_valid = false;
234                 nvkm_warn(subdev, "found invalid sensor id: %i, power reading"
235                           "might be invalid\n", id);
236                 return NULL;
237         }
238
239         sensor = kmalloc(sizeof(*sensor), GFP_KERNEL);
240         if (!sensor)
241                 return NULL;
242
243         list_add_tail(&sensor->head, &iccsense->sensors);
244         sensor->id = id;
245         sensor->type = extdev.type;
246         sensor->i2c = &i2c_bus->i2c;
247         sensor->addr = addr;
248         sensor->rail_mask = 0x0;
249         return sensor;
250 }
251
252 static struct nvkm_iccsense_sensor*
253 nvkm_iccsense_get_sensor(struct nvkm_iccsense *iccsense, u8 id)
254 {
255         struct nvkm_iccsense_sensor *sensor;
256         list_for_each_entry(sensor, &iccsense->sensors, head) {
257                 if (sensor->id == id)
258                         return sensor;
259         }
260         return nvkm_iccsense_create_sensor(iccsense, id);
261 }
262
263 static int
264 nvkm_iccsense_oneinit(struct nvkm_subdev *subdev)
265 {
266         struct nvkm_iccsense *iccsense = nvkm_iccsense(subdev);
267         struct nvkm_bios *bios = subdev->device->bios;
268         struct nvbios_iccsense stbl;
269         int i;
270
271         if (!bios || nvbios_iccsense_parse(bios, &stbl) || !stbl.nr_entry)
272                 return 0;
273
274         iccsense->data_valid = true;
275         for (i = 0; i < stbl.nr_entry; ++i) {
276                 struct pwr_rail_t *r = &stbl.rail[i];
277                 struct nvkm_iccsense_rail *rail;
278                 struct nvkm_iccsense_sensor *sensor;
279                 int (*read)(struct nvkm_iccsense *,
280                             struct nvkm_iccsense_rail *);
281
282                 if (!r->mode || r->resistor_mohm == 0)
283                         continue;
284
285                 sensor = nvkm_iccsense_get_sensor(iccsense, r->extdev_id);
286                 if (!sensor)
287                         continue;
288
289                 switch (sensor->type) {
290                 case NVBIOS_EXTDEV_INA209:
291                         if (r->rail != 0)
292                                 continue;
293                         read = nvkm_iccsense_ina209_read;
294                         break;
295                 case NVBIOS_EXTDEV_INA219:
296                         if (r->rail != 0)
297                                 continue;
298                         read = nvkm_iccsense_ina219_read;
299                         break;
300                 case NVBIOS_EXTDEV_INA3221:
301                         if (r->rail >= 3)
302                                 continue;
303                         read = nvkm_iccsense_ina3221_read;
304                         break;
305                 default:
306                         continue;
307                 }
308
309                 rail = kmalloc(sizeof(*rail), GFP_KERNEL);
310                 if (!rail)
311                         return -ENOMEM;
312                 sensor->rail_mask |= 1 << r->rail;
313                 rail->read = read;
314                 rail->sensor = sensor;
315                 rail->idx = r->rail;
316                 rail->mohm = r->resistor_mohm;
317                 list_add_tail(&rail->head, &iccsense->rails);
318         }
319         return 0;
320 }
321
322 static int
323 nvkm_iccsense_init(struct nvkm_subdev *subdev)
324 {
325         struct nvkm_iccsense *iccsense = nvkm_iccsense(subdev);
326         struct nvkm_iccsense_sensor *sensor;
327         list_for_each_entry(sensor, &iccsense->sensors, head)
328                 nvkm_iccsense_sensor_config(iccsense, sensor);
329         return 0;
330 }
331
332 struct nvkm_subdev_func iccsense_func = {
333         .oneinit = nvkm_iccsense_oneinit,
334         .init = nvkm_iccsense_init,
335         .dtor = nvkm_iccsense_dtor,
336 };
337
338 void
339 nvkm_iccsense_ctor(struct nvkm_device *device, int index,
340                    struct nvkm_iccsense *iccsense)
341 {
342         nvkm_subdev_ctor(&iccsense_func, device, index, &iccsense->subdev);
343 }
344
345 int
346 nvkm_iccsense_new_(struct nvkm_device *device, int index,
347                    struct nvkm_iccsense **iccsense)
348 {
349         if (!(*iccsense = kzalloc(sizeof(**iccsense), GFP_KERNEL)))
350                 return -ENOMEM;
351         INIT_LIST_HEAD(&(*iccsense)->sensors);
352         INIT_LIST_HEAD(&(*iccsense)->rails);
353         nvkm_iccsense_ctor(device, index, *iccsense);
354         return 0;
355 }