base.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  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. #include <subdev/bios.h>
  26. #include <subdev/bios/extdev.h>
  27. #include <subdev/bios/iccsense.h>
  28. #include <subdev/bios/power_budget.h>
  29. #include <subdev/i2c.h>
  30. static bool
  31. nvkm_iccsense_validate_device(struct i2c_adapter *i2c, u8 addr,
  32. enum nvbios_extdev_type type)
  33. {
  34. switch (type) {
  35. case NVBIOS_EXTDEV_INA209:
  36. case NVBIOS_EXTDEV_INA219:
  37. return nv_rd16i2cr(i2c, addr, 0x0) >= 0;
  38. case NVBIOS_EXTDEV_INA3221:
  39. return nv_rd16i2cr(i2c, addr, 0xff) == 0x3220 &&
  40. nv_rd16i2cr(i2c, addr, 0xfe) == 0x5449;
  41. default:
  42. return false;
  43. }
  44. }
  45. static int
  46. nvkm_iccsense_poll_lane(struct i2c_adapter *i2c, u8 addr, u8 shunt_reg,
  47. u8 shunt_shift, u8 bus_reg, u8 bus_shift, u8 shunt,
  48. u16 lsb)
  49. {
  50. int vshunt = nv_rd16i2cr(i2c, addr, shunt_reg);
  51. int vbus = nv_rd16i2cr(i2c, addr, bus_reg);
  52. if (vshunt < 0 || vbus < 0)
  53. return -EINVAL;
  54. vshunt >>= shunt_shift;
  55. vbus >>= bus_shift;
  56. return vbus * vshunt * lsb / shunt;
  57. }
  58. static int
  59. nvkm_iccsense_ina2x9_read(struct nvkm_iccsense *iccsense,
  60. struct nvkm_iccsense_rail *rail,
  61. u8 shunt_reg, u8 bus_reg)
  62. {
  63. return nvkm_iccsense_poll_lane(rail->sensor->i2c, rail->sensor->addr,
  64. shunt_reg, 0, bus_reg, 3, rail->mohm,
  65. 10 * 4);
  66. }
  67. static int
  68. nvkm_iccsense_ina209_read(struct nvkm_iccsense *iccsense,
  69. struct nvkm_iccsense_rail *rail)
  70. {
  71. return nvkm_iccsense_ina2x9_read(iccsense, rail, 3, 4);
  72. }
  73. static int
  74. nvkm_iccsense_ina219_read(struct nvkm_iccsense *iccsense,
  75. struct nvkm_iccsense_rail *rail)
  76. {
  77. return nvkm_iccsense_ina2x9_read(iccsense, rail, 1, 2);
  78. }
  79. static int
  80. nvkm_iccsense_ina3221_read(struct nvkm_iccsense *iccsense,
  81. struct nvkm_iccsense_rail *rail)
  82. {
  83. return nvkm_iccsense_poll_lane(rail->sensor->i2c, rail->sensor->addr,
  84. 1 + (rail->idx * 2), 3,
  85. 2 + (rail->idx * 2), 3, rail->mohm,
  86. 40 * 8);
  87. }
  88. static void
  89. nvkm_iccsense_sensor_config(struct nvkm_iccsense *iccsense,
  90. struct nvkm_iccsense_sensor *sensor)
  91. {
  92. struct nvkm_subdev *subdev = &iccsense->subdev;
  93. nvkm_trace(subdev, "write config of extdev %i: 0x%04x\n", sensor->id, sensor->config);
  94. nv_wr16i2cr(sensor->i2c, sensor->addr, 0x00, sensor->config);
  95. }
  96. int
  97. nvkm_iccsense_read_all(struct nvkm_iccsense *iccsense)
  98. {
  99. int result = 0;
  100. struct nvkm_iccsense_rail *rail;
  101. if (!iccsense)
  102. return -EINVAL;
  103. list_for_each_entry(rail, &iccsense->rails, head) {
  104. int res;
  105. if (!rail->read)
  106. return -ENODEV;
  107. res = rail->read(iccsense, rail);
  108. if (res < 0)
  109. return res;
  110. result += res;
  111. }
  112. return result;
  113. }
  114. static void *
  115. nvkm_iccsense_dtor(struct nvkm_subdev *subdev)
  116. {
  117. struct nvkm_iccsense *iccsense = nvkm_iccsense(subdev);
  118. struct nvkm_iccsense_sensor *sensor, *tmps;
  119. struct nvkm_iccsense_rail *rail, *tmpr;
  120. list_for_each_entry_safe(sensor, tmps, &iccsense->sensors, head) {
  121. list_del(&sensor->head);
  122. kfree(sensor);
  123. }
  124. list_for_each_entry_safe(rail, tmpr, &iccsense->rails, head) {
  125. list_del(&rail->head);
  126. kfree(rail);
  127. }
  128. return iccsense;
  129. }
  130. static struct nvkm_iccsense_sensor*
  131. nvkm_iccsense_create_sensor(struct nvkm_iccsense *iccsense, u8 id)
  132. {
  133. struct nvkm_subdev *subdev = &iccsense->subdev;
  134. struct nvkm_bios *bios = subdev->device->bios;
  135. struct nvkm_i2c *i2c = subdev->device->i2c;
  136. struct nvbios_extdev_func extdev;
  137. struct nvkm_i2c_bus *i2c_bus;
  138. struct nvkm_iccsense_sensor *sensor;
  139. u8 addr;
  140. if (!i2c || !bios || nvbios_extdev_parse(bios, id, &extdev))
  141. return NULL;
  142. if (extdev.type == 0xff)
  143. return NULL;
  144. if (extdev.type != NVBIOS_EXTDEV_INA209 &&
  145. extdev.type != NVBIOS_EXTDEV_INA219 &&
  146. extdev.type != NVBIOS_EXTDEV_INA3221) {
  147. iccsense->data_valid = false;
  148. nvkm_error(subdev, "Unknown sensor type %x, power reading "
  149. "disabled\n", extdev.type);
  150. return NULL;
  151. }
  152. if (extdev.bus)
  153. i2c_bus = nvkm_i2c_bus_find(i2c, NVKM_I2C_BUS_SEC);
  154. else
  155. i2c_bus = nvkm_i2c_bus_find(i2c, NVKM_I2C_BUS_PRI);
  156. if (!i2c_bus)
  157. return NULL;
  158. addr = extdev.addr >> 1;
  159. if (!nvkm_iccsense_validate_device(&i2c_bus->i2c, addr,
  160. extdev.type)) {
  161. iccsense->data_valid = false;
  162. nvkm_warn(subdev, "found invalid sensor id: %i, power reading"
  163. "might be invalid\n", id);
  164. return NULL;
  165. }
  166. sensor = kmalloc(sizeof(*sensor), GFP_KERNEL);
  167. if (!sensor)
  168. return NULL;
  169. list_add_tail(&sensor->head, &iccsense->sensors);
  170. sensor->id = id;
  171. sensor->type = extdev.type;
  172. sensor->i2c = &i2c_bus->i2c;
  173. sensor->addr = addr;
  174. sensor->config = 0x0;
  175. return sensor;
  176. }
  177. static struct nvkm_iccsense_sensor*
  178. nvkm_iccsense_get_sensor(struct nvkm_iccsense *iccsense, u8 id)
  179. {
  180. struct nvkm_iccsense_sensor *sensor;
  181. list_for_each_entry(sensor, &iccsense->sensors, head) {
  182. if (sensor->id == id)
  183. return sensor;
  184. }
  185. return nvkm_iccsense_create_sensor(iccsense, id);
  186. }
  187. static int
  188. nvkm_iccsense_oneinit(struct nvkm_subdev *subdev)
  189. {
  190. struct nvkm_iccsense *iccsense = nvkm_iccsense(subdev);
  191. struct nvkm_bios *bios = subdev->device->bios;
  192. struct nvbios_power_budget budget;
  193. struct nvbios_iccsense stbl;
  194. int i, ret;
  195. if (!bios)
  196. return 0;
  197. ret = nvbios_power_budget_header(bios, &budget);
  198. if (!ret && budget.cap_entry != 0xff) {
  199. struct nvbios_power_budget_entry entry;
  200. ret = nvbios_power_budget_entry(bios, &budget,
  201. budget.cap_entry, &entry);
  202. if (!ret) {
  203. iccsense->power_w_max = entry.avg_w;
  204. iccsense->power_w_crit = entry.max_w;
  205. }
  206. }
  207. if (nvbios_iccsense_parse(bios, &stbl) || !stbl.nr_entry)
  208. return 0;
  209. iccsense->data_valid = true;
  210. for (i = 0; i < stbl.nr_entry; ++i) {
  211. struct pwr_rail_t *pwr_rail = &stbl.rail[i];
  212. struct nvkm_iccsense_sensor *sensor;
  213. int r;
  214. if (pwr_rail->mode != 1 || !pwr_rail->resistor_count)
  215. continue;
  216. sensor = nvkm_iccsense_get_sensor(iccsense, pwr_rail->extdev_id);
  217. if (!sensor)
  218. continue;
  219. if (!sensor->config)
  220. sensor->config = pwr_rail->config;
  221. else if (sensor->config != pwr_rail->config)
  222. nvkm_error(subdev, "config mismatch found for extdev %i\n", pwr_rail->extdev_id);
  223. for (r = 0; r < pwr_rail->resistor_count; ++r) {
  224. struct nvkm_iccsense_rail *rail;
  225. struct pwr_rail_resistor_t *res = &pwr_rail->resistors[r];
  226. int (*read)(struct nvkm_iccsense *,
  227. struct nvkm_iccsense_rail *);
  228. if (!res->mohm || !res->enabled)
  229. continue;
  230. switch (sensor->type) {
  231. case NVBIOS_EXTDEV_INA209:
  232. read = nvkm_iccsense_ina209_read;
  233. break;
  234. case NVBIOS_EXTDEV_INA219:
  235. read = nvkm_iccsense_ina219_read;
  236. break;
  237. case NVBIOS_EXTDEV_INA3221:
  238. read = nvkm_iccsense_ina3221_read;
  239. break;
  240. default:
  241. continue;
  242. }
  243. rail = kmalloc(sizeof(*rail), GFP_KERNEL);
  244. if (!rail)
  245. return -ENOMEM;
  246. rail->read = read;
  247. rail->sensor = sensor;
  248. rail->idx = r;
  249. rail->mohm = res->mohm;
  250. nvkm_debug(subdev, "create rail for extdev %i: { idx: %i, mohm: %i }\n", pwr_rail->extdev_id, r, rail->mohm);
  251. list_add_tail(&rail->head, &iccsense->rails);
  252. }
  253. }
  254. return 0;
  255. }
  256. static int
  257. nvkm_iccsense_init(struct nvkm_subdev *subdev)
  258. {
  259. struct nvkm_iccsense *iccsense = nvkm_iccsense(subdev);
  260. struct nvkm_iccsense_sensor *sensor;
  261. list_for_each_entry(sensor, &iccsense->sensors, head)
  262. nvkm_iccsense_sensor_config(iccsense, sensor);
  263. return 0;
  264. }
  265. static const struct nvkm_subdev_func
  266. iccsense_func = {
  267. .oneinit = nvkm_iccsense_oneinit,
  268. .init = nvkm_iccsense_init,
  269. .dtor = nvkm_iccsense_dtor,
  270. };
  271. void
  272. nvkm_iccsense_ctor(struct nvkm_device *device, int index,
  273. struct nvkm_iccsense *iccsense)
  274. {
  275. nvkm_subdev_ctor(&iccsense_func, device, index, &iccsense->subdev);
  276. }
  277. int
  278. nvkm_iccsense_new_(struct nvkm_device *device, int index,
  279. struct nvkm_iccsense **iccsense)
  280. {
  281. if (!(*iccsense = kzalloc(sizeof(**iccsense), GFP_KERNEL)))
  282. return -ENOMEM;
  283. INIT_LIST_HEAD(&(*iccsense)->sensors);
  284. INIT_LIST_HEAD(&(*iccsense)->rails);
  285. nvkm_iccsense_ctor(device, index, *iccsense);
  286. return 0;
  287. }