-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
drm/nouveau/gpio: port gpio to subdev interfaces
v2: Ben Skeggs <bskeggs@redhat.com> - rebase on top of v3.6-rc6 with gpio reset patch integrated already Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
- Loading branch information
Ben Skeggs
committed
Oct 3, 2012
1 parent
cd42439
commit e0996ae
Showing
33 changed files
with
933 additions
and
503 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
#ifndef __NVBIOS_DCB_H__ | ||
#define __NVBIOS_DCB_H__ | ||
|
||
enum dcb_output_type { | ||
DCB_OUTPUT_ANALOG = 0x0, | ||
DCB_OUTPUT_TV = 0x1, | ||
DCB_OUTPUT_TMDS = 0x2, | ||
DCB_OUTPUT_LVDS = 0x3, | ||
DCB_OUTPUT_DP = 0x4, | ||
DCB_OUTPUT_EOL = 0xe, | ||
DCB_OUTPUT_UNUSED = 0xf, | ||
}; | ||
|
||
u16 dcb_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *ent, u8 *len); | ||
u16 dcb_outp(struct nouveau_bios *, u8 idx, u8 *ver, u8 *len); | ||
int dcb_outp_foreach(struct nouveau_bios *, void *data, int (*exec) | ||
(struct nouveau_bios *, void *, int index, u16 entry)); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#ifndef __NVBIOS_GPIO_H__ | ||
#define __NVBIOS_GPIO_H__ | ||
|
||
struct nouveau_bios; | ||
|
||
enum dcb_gpio_func_name { | ||
DCB_GPIO_PANEL_POWER = 0x01, | ||
DCB_GPIO_TVDAC0 = 0x0c, | ||
DCB_GPIO_TVDAC1 = 0x2d, | ||
DCB_GPIO_PWM_FAN = 0x09, | ||
DCB_GPIO_FAN_SENSE = 0x3d, | ||
DCB_GPIO_UNUSED = 0xff | ||
}; | ||
|
||
struct dcb_gpio_func { | ||
u8 func; | ||
u8 line; | ||
u8 log[2]; | ||
}; | ||
|
||
u16 dcb_gpio_table(struct nouveau_bios *); | ||
u16 dcb_gpio_entry(struct nouveau_bios *, int idx, int ent, u8 *ver); | ||
int dcb_gpio_parse(struct nouveau_bios *, int idx, u8 func, u8 line, | ||
struct dcb_gpio_func *); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,71 +1,64 @@ | ||
/* | ||
* Copyright 2011 Red Hat Inc. | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a | ||
* copy of this software and associated documentation files (the "Software"), | ||
* to deal in the Software without restriction, including without limitation | ||
* the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
* and/or sell copies of the Software, and to permit persons to whom the | ||
* Software is furnished to do so, subject to the following conditions: | ||
* | ||
* The above copyright notice and this permission notice shall be included in | ||
* all copies or substantial portions of the Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
* OTHER DEALINGS IN THE SOFTWARE. | ||
*/ | ||
|
||
#ifndef __NOUVEAU_GPIO_H__ | ||
#define __NOUVEAU_GPIO_H__ | ||
|
||
struct gpio_func { | ||
u8 func; | ||
u8 line; | ||
u8 log[2]; | ||
}; | ||
#include <core/subdev.h> | ||
#include <core/device.h> | ||
|
||
/* nouveau_gpio.c */ | ||
int nouveau_gpio_create(struct drm_device *); | ||
void nouveau_gpio_destroy(struct drm_device *); | ||
int nouveau_gpio_init(struct drm_device *); | ||
void nouveau_gpio_fini(struct drm_device *); | ||
void nouveau_gpio_reset(struct drm_device *); | ||
int nouveau_gpio_drive(struct drm_device *, int idx, int line, | ||
int dir, int out); | ||
int nouveau_gpio_sense(struct drm_device *, int idx, int line); | ||
int nouveau_gpio_find(struct drm_device *, int idx, u8 tag, u8 line, | ||
struct gpio_func *); | ||
int nouveau_gpio_set(struct drm_device *, int idx, u8 tag, u8 line, int state); | ||
int nouveau_gpio_get(struct drm_device *, int idx, u8 tag, u8 line); | ||
int nouveau_gpio_irq(struct drm_device *, int idx, u8 tag, u8 line, bool on); | ||
void nouveau_gpio_isr(struct drm_device *, int idx, u32 mask); | ||
int nouveau_gpio_isr_add(struct drm_device *, int idx, u8 tag, u8 line, | ||
void (*)(void *, int state), void *data); | ||
void nouveau_gpio_isr_del(struct drm_device *, int idx, u8 tag, u8 line, | ||
void (*)(void *, int state), void *data); | ||
#include <subdev/bios.h> | ||
#include <subdev/bios/gpio.h> | ||
|
||
static inline bool | ||
nouveau_gpio_func_valid(struct drm_device *dev, u8 tag) | ||
{ | ||
struct gpio_func func; | ||
return (nouveau_gpio_find(dev, 0, tag, 0xff, &func)) == 0; | ||
} | ||
struct nouveau_gpio { | ||
struct nouveau_subdev base; | ||
|
||
static inline int | ||
nouveau_gpio_func_set(struct drm_device *dev, u8 tag, int state) | ||
{ | ||
return nouveau_gpio_set(dev, 0, tag, 0xff, state); | ||
} | ||
/* hardware interfaces */ | ||
void (*reset)(struct nouveau_gpio *); | ||
int (*drive)(struct nouveau_gpio *, int line, int dir, int out); | ||
int (*sense)(struct nouveau_gpio *, int line); | ||
void (*irq_enable)(struct nouveau_gpio *, int line, bool); | ||
|
||
/* software interfaces */ | ||
int (*find)(struct nouveau_gpio *, int idx, u8 tag, u8 line, | ||
struct dcb_gpio_func *); | ||
int (*set)(struct nouveau_gpio *, int idx, u8 tag, u8 line, int state); | ||
int (*get)(struct nouveau_gpio *, int idx, u8 tag, u8 line); | ||
int (*irq)(struct nouveau_gpio *, int idx, u8 tag, u8 line, bool on); | ||
|
||
static inline int | ||
nouveau_gpio_func_get(struct drm_device *dev, u8 tag) | ||
/* interrupt handling */ | ||
struct list_head isr; | ||
spinlock_t lock; | ||
|
||
void (*isr_run)(struct nouveau_gpio *, int idx, u32 mask); | ||
int (*isr_add)(struct nouveau_gpio *, int idx, u8 tag, u8 line, | ||
void (*)(void *, int state), void *data); | ||
void (*isr_del)(struct nouveau_gpio *, int idx, u8 tag, u8 line, | ||
void (*)(void *, int state), void *data); | ||
}; | ||
|
||
static inline struct nouveau_gpio * | ||
nouveau_gpio(void *obj) | ||
{ | ||
return nouveau_gpio_get(dev, 0, tag, 0xff); | ||
return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_GPIO]; | ||
} | ||
|
||
#define nouveau_gpio_create(p,e,o,d) \ | ||
nouveau_gpio_create_((p), (e), (o), sizeof(**d), (void **)d) | ||
#define nouveau_gpio_destroy(p) \ | ||
nouveau_subdev_destroy(&(p)->base) | ||
#define nouveau_gpio_fini(p,s) \ | ||
nouveau_subdev_fini(&(p)->base, (s)) | ||
|
||
int nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *, | ||
struct nouveau_oclass *, int, void **); | ||
int nouveau_gpio_init(struct nouveau_gpio *); | ||
|
||
extern struct nouveau_oclass nv10_gpio_oclass; | ||
extern struct nouveau_oclass nv50_gpio_oclass; | ||
extern struct nouveau_oclass nvd0_gpio_oclass; | ||
|
||
void nv50_gpio_dtor(struct nouveau_object *); | ||
int nv50_gpio_init(struct nouveau_object *); | ||
int nv50_gpio_fini(struct nouveau_object *, bool); | ||
void nv50_gpio_intr(struct nouveau_subdev *); | ||
void nv50_gpio_irq_enable(struct nouveau_gpio *, int line, bool); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
/* | ||
* Copyright 2012 Red Hat Inc. | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a | ||
* copy of this software and associated documentation files (the "Software"), | ||
* to deal in the Software without restriction, including without limitation | ||
* the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
* and/or sell copies of the Software, and to permit persons to whom the | ||
* Software is furnished to do so, subject to the following conditions: | ||
* | ||
* The above copyright notice and this permission notice shall be included in | ||
* all copies or substantial portions of the Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
* OTHER DEALINGS IN THE SOFTWARE. | ||
* | ||
* Authors: Ben Skeggs | ||
*/ | ||
|
||
#include "core/device.h" | ||
|
||
#include "subdev/bios.h" | ||
#include "subdev/bios/dcb.h" | ||
|
||
u16 | ||
dcb_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) | ||
{ | ||
struct nouveau_device *device = nv_device(bios); | ||
u16 dcb = 0x0000; | ||
|
||
if (device->card_type > NV_04) | ||
dcb = nv_ro16(bios, 0x36); | ||
if (!dcb) { | ||
nv_warn(bios, "DCB table not found\n"); | ||
return dcb; | ||
} | ||
|
||
*ver = nv_ro08(bios, dcb); | ||
|
||
if (*ver >= 0x41) { | ||
nv_warn(bios, "DCB *ver 0x%02x unknown\n", *ver); | ||
return 0x0000; | ||
} else | ||
if (*ver >= 0x30) { | ||
if (nv_ro32(bios, dcb + 6) == 0x4edcbdcb) { | ||
*hdr = nv_ro08(bios, dcb + 1); | ||
*cnt = nv_ro08(bios, dcb + 2); | ||
*len = nv_ro08(bios, dcb + 3); | ||
return dcb; | ||
} | ||
} else | ||
if (*ver >= 0x20) { | ||
if (nv_ro32(bios, dcb + 4) == 0x4edcbdcb) { | ||
u16 i2c = nv_ro16(bios, dcb + 2); | ||
*hdr = 8; | ||
*cnt = (i2c - dcb) / 8; | ||
*len = 8; | ||
return dcb; | ||
} | ||
} else | ||
if (*ver >= 0x15) { | ||
if (!nv_strncmp(bios, dcb - 7, 7, "DEV_REC")) { | ||
u16 i2c = nv_ro16(bios, dcb + 2); | ||
*hdr = 4; | ||
*cnt = (i2c - dcb) / 10; | ||
*len = 10; | ||
return dcb; | ||
} | ||
} else { | ||
/* | ||
* v1.4 (some NV15/16, NV11+) seems the same as v1.5, but | ||
* always has the same single (crt) entry, even when tv-out | ||
* present, so the conclusion is this version cannot really | ||
* be used. | ||
* | ||
* v1.2 tables (some NV6/10, and NV15+) normally have the | ||
* same 5 entries, which are not specific to the card and so | ||
* no use. | ||
* | ||
* v1.2 does have an I2C table that read_dcb_i2c_table can | ||
* handle, but cards exist (nv11 in #14821) with a bad i2c | ||
* table pointer, so use the indices parsed in | ||
* parse_bmp_structure. | ||
* | ||
* v1.1 (NV5+, maybe some NV4) is entirely unhelpful | ||
*/ | ||
nv_warn(bios, "DCB contains no useful data\n"); | ||
return 0x0000; | ||
} | ||
|
||
nv_warn(bios, "DCB header validation failed\n"); | ||
return 0x0000; | ||
} | ||
|
||
u16 | ||
dcb_outp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len) | ||
{ | ||
u8 hdr, cnt; | ||
u16 dcb = dcb_table(bios, ver, &hdr, &cnt, len); | ||
if (dcb && idx < cnt) | ||
return dcb + hdr + (idx * *len); | ||
return 0x0000; | ||
} | ||
|
||
int | ||
dcb_outp_foreach(struct nouveau_bios *bios, void *data, | ||
int (*exec)(struct nouveau_bios *, void *, int, u16)) | ||
{ | ||
int ret, idx = -1; | ||
u8 ver, len; | ||
u16 outp; | ||
|
||
while ((outp = dcb_outp(bios, ++idx, &ver, &len))) { | ||
if (nv_ro32(bios, outp) == 0x00000000) | ||
break; /* seen on an NV11 with DCB v1.5 */ | ||
if (nv_ro32(bios, outp) == 0xffffffff) | ||
break; /* seen on an NV17 with DCB v2.0 */ | ||
|
||
if (nv_ro08(bios, outp) == DCB_OUTPUT_UNUSED) | ||
continue; | ||
if (nv_ro08(bios, outp) == DCB_OUTPUT_EOL) | ||
break; | ||
|
||
ret = exec(bios, data, idx, outp); | ||
if (ret) | ||
return ret; | ||
} | ||
|
||
return 0; | ||
} |
Oops, something went wrong.