1c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs/*
2c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs * Copyright 2013 Red Hat Inc.
3c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs *
4c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs * Permission is hereby granted, free of charge, to any person obtaining a
5c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs * copy of this software and associated documentation files (the "Software"),
6c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs * to deal in the Software without restriction, including without limitation
7c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs * and/or sell copies of the Software, and to permit persons to whom the
9c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs * Software is furnished to do so, subject to the following conditions:
10c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs *
11c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs * The above copyright notice and this permission notice shall be included in
12c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs * all copies or substantial portions of the Software.
13c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs *
14c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs * OTHER DEALINGS IN THE SOFTWARE.
21c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs *
22c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs * Authors: Ben Skeggs
23c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs */
24c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs
25c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs#include <subdev/volt.h>
26c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs#include <subdev/gpio.h>
27c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs#include <subdev/bios/gpio.h>
28c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs
29c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggsstatic const u8 tags[] = {
30c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	DCB_GPIO_VID0, DCB_GPIO_VID1, DCB_GPIO_VID2, DCB_GPIO_VID3,
31c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	DCB_GPIO_VID4, DCB_GPIO_VID5, DCB_GPIO_VID6, DCB_GPIO_VID7,
32c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs};
33c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs
34c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggsint
35c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggsnouveau_voltgpio_get(struct nouveau_volt *volt)
36c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs{
37c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	struct nouveau_gpio *gpio = nouveau_gpio(volt);
38c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	u8 vid = 0;
39c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	int i;
40c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs
41c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	for (i = 0; i < ARRAY_SIZE(tags); i++) {
42c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs		if (volt->vid_mask & (1 << i)) {
43c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs			int ret = gpio->get(gpio, 0, tags[i], 0xff);
44c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs			if (ret < 0)
45c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs				return ret;
46c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs			vid |= ret << i;
47c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs		}
48c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	}
49c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs
50c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	return vid;
51c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs}
52c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs
53c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggsint
54c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggsnouveau_voltgpio_set(struct nouveau_volt *volt, u8 vid)
55c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs{
56c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	struct nouveau_gpio *gpio = nouveau_gpio(volt);
57c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	int i;
58c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs
59c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	for (i = 0; i < ARRAY_SIZE(tags); i++, vid >>= 1) {
60c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs		if (volt->vid_mask & (1 << i)) {
61c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs			int ret = gpio->set(gpio, 0, tags[i], 0xff, vid & 1);
62c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs			if (ret < 0)
63c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs				return ret;
64c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs		}
65c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	}
66c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs
67c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	return 0;
68c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs}
69c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs
70c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggsint
71c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggsnouveau_voltgpio_init(struct nouveau_volt *volt)
72c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs{
73c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	struct nouveau_gpio *gpio = nouveau_gpio(volt);
74c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	struct dcb_gpio_func func;
75c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	int i;
76c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs
77c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	/* check we have gpio function info for each vid bit.  on some
78c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	 * boards (ie. nvs295) the vid mask has more bits than there
79c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	 * are valid gpio functions... from traces, nvidia appear to
80c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	 * just touch the existing ones, so let's mask off the invalid
81c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	 * bits and continue with life
82c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	 */
83c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	for (i = 0; i < ARRAY_SIZE(tags); i++) {
84c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs		if (volt->vid_mask & (1 << i)) {
85c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs			int ret = gpio->find(gpio, 0, tags[i], 0xff, &func);
86c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs			if (ret) {
87c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs				if (ret != -ENOENT)
88c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs					return ret;
89c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs				nv_debug(volt, "VID bit %d has no GPIO\n", i);
90c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs				volt->vid_mask &= ~(1 << i);
91c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs			}
92c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs		}
93c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	}
94c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs
95c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs	return 0;
96c9c0ccae48e27b767e98a4c120976e43195dd3a7Ben Skeggs}
97