summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nv10_gpio.c
diff options
context:
space:
mode:
authorBen Skeggs2011-11-21 07:41:48 +0100
committerBen Skeggs2011-12-21 10:01:45 +0100
commita0b25635515ef5049f93b032a1e37f18b16e0f6f (patch)
tree34c25948a2fd7b8eadf46418d767d43c9a64c06b /drivers/gpu/drm/nouveau/nv10_gpio.c
parentdrm/nouveau: just pass gpio line to pwm_*, not entire gpio struct (diff)
downloadkernel-qcow2-linux-a0b25635515ef5049f93b032a1e37f18b16e0f6f.tar.gz
kernel-qcow2-linux-a0b25635515ef5049f93b032a1e37f18b16e0f6f.tar.xz
kernel-qcow2-linux-a0b25635515ef5049f93b032a1e37f18b16e0f6f.zip
drm/nouveau/gpio: reimplement as nouveau_gpio.c, fixing a number of issues
- moves out of nouveau_bios.c and demagics the logical state definitions - simplifies chipset-specific driver interface - makes most of gpio irq handling common, will use for nv4x hpd later - api extended to allow both direct gpio access, and access using the logical function states - api extended to allow for future use of gpio extender chips - pre-nv50 was handled very badly, the main issue being that all GPIOs were being treated as output-only. - fixes nvd0 so gpio changes actually stick, magic reg needs bashing Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv10_gpio.c')
-rw-r--r--drivers/gpu/drm/nouveau/nv10_gpio.c94
1 files changed, 42 insertions, 52 deletions
diff --git a/drivers/gpu/drm/nouveau/nv10_gpio.c b/drivers/gpu/drm/nouveau/nv10_gpio.c
index 748c9f739116..419d6495649b 100644
--- a/drivers/gpu/drm/nouveau/nv10_gpio.c
+++ b/drivers/gpu/drm/nouveau/nv10_gpio.c
@@ -28,65 +28,55 @@
#include "nouveau_drv.h"
#include "nouveau_hw.h"
-static bool
-get_gpio_location(struct dcb_gpio_entry *ent, uint32_t *reg, uint32_t *shift,
- uint32_t *mask)
-{
- if (ent->line < 2) {
- *reg = NV_PCRTC_GPIO;
- *shift = ent->line * 16;
- *mask = 0x11;
-
- } else if (ent->line < 10) {
- *reg = NV_PCRTC_GPIO_EXT;
- *shift = (ent->line - 2) * 4;
- *mask = 0x3;
-
- } else if (ent->line < 14) {
- *reg = NV_PCRTC_850;
- *shift = (ent->line - 10) * 4;
- *mask = 0x3;
-
- } else {
- return false;
- }
-
- return true;
-}
-
int
-nv10_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag)
+nv10_gpio_sense(struct drm_device *dev, int line)
{
- struct dcb_gpio_entry *ent = nouveau_bios_gpio_entry(dev, tag);
- uint32_t reg, shift, mask, value;
-
- if (!ent)
- return -ENODEV;
-
- if (!get_gpio_location(ent, &reg, &shift, &mask))
- return -ENODEV;
-
- value = NVReadCRTC(dev, 0, reg) >> shift;
+ if (line < 2) {
+ line = line * 16;
+ line = NVReadCRTC(dev, 0, NV_PCRTC_GPIO) >> line;
+ return !!(line & 0x0100);
+ } else
+ if (line < 10) {
+ line = (line - 2) * 4;
+ line = NVReadCRTC(dev, 0, NV_PCRTC_GPIO_EXT) >> line;
+ return !!(line & 0x04);
+ } else
+ if (line < 14) {
+ line = (line - 10) * 4;
+ line = NVReadCRTC(dev, 0, NV_PCRTC_850) >> line;
+ return !!(line & 0x04);
+ }
- return (value & 1) == ent->state[1];
+ return -EINVAL;
}
int
-nv10_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state)
+nv10_gpio_drive(struct drm_device *dev, int line, int dir, int out)
{
- struct dcb_gpio_entry *ent = nouveau_bios_gpio_entry(dev, tag);
- uint32_t reg, shift, mask, value;
-
- if (!ent)
- return -ENODEV;
-
- if (!get_gpio_location(ent, &reg, &shift, &mask))
- return -ENODEV;
-
- value = ent->state[state & 1] << shift;
- mask = ~(mask << shift);
-
- NVWriteCRTC(dev, 0, reg, value | (NVReadCRTC(dev, 0, reg) & mask));
+ u32 reg, mask, data;
+
+ if (line < 2) {
+ line = line * 16;
+ reg = NV_PCRTC_GPIO;
+ mask = 0x00000011;
+ data = (dir << 4) | out;
+ } else
+ if (line < 10) {
+ line = (line - 2) * 4;
+ reg = NV_PCRTC_GPIO_EXT;
+ mask = 0x00000003 << ((line - 2) * 4);
+ data = (dir << 1) | out;
+ } else
+ if (line < 14) {
+ line = (line - 10) * 4;
+ reg = NV_PCRTC_850;
+ mask = 0x00000003;
+ data = (dir << 1) | out;
+ } else {
+ return -EINVAL;
+ }
+ mask = NVReadCRTC(dev, 0, reg) & ~(mask << line);
+ NVWriteCRTC(dev, 0, reg, mask | (data << line));
return 0;
}