diff options
-rw-r--r-- | drivers/gpu/drm/nouveau/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_bios.c | 206 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_bios.h | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_connector.c | 24 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_dp.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.h | 47 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_gpio.c | 400 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_gpio.h | 71 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_pm.c | 43 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_state.c | 64 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_volt.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv04_dac.c | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv10_gpio.c | 94 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv17_tv.c | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_display.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_gpio.c | 272 |
16 files changed, 653 insertions, 646 deletions
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index c152a03d287f..9f27e3d9e69a 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile | |||
@@ -11,7 +11,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ | |||
11 | nouveau_display.o nouveau_connector.o nouveau_fbcon.o \ | 11 | nouveau_display.o nouveau_connector.o nouveau_fbcon.o \ |
12 | nouveau_hdmi.o nouveau_dp.o nouveau_ramht.o \ | 12 | nouveau_hdmi.o nouveau_dp.o nouveau_ramht.o \ |
13 | nouveau_pm.o nouveau_volt.o nouveau_perf.o nouveau_temp.o \ | 13 | nouveau_pm.o nouveau_volt.o nouveau_perf.o nouveau_temp.o \ |
14 | nouveau_mm.o nouveau_vm.o nouveau_mxm.o \ | 14 | nouveau_mm.o nouveau_vm.o nouveau_mxm.o nouveau_gpio.o \ |
15 | nv04_timer.o \ | 15 | nv04_timer.o \ |
16 | nv04_mc.o nv40_mc.o nv50_mc.o \ | 16 | nv04_mc.o nv40_mc.o nv50_mc.o \ |
17 | nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o nvc0_fb.o \ | 17 | nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o nvc0_fb.o \ |
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index f8df37285ba7..e5cbead85e50 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include "nouveau_drv.h" | 27 | #include "nouveau_drv.h" |
28 | #include "nouveau_hw.h" | 28 | #include "nouveau_hw.h" |
29 | #include "nouveau_encoder.h" | 29 | #include "nouveau_encoder.h" |
30 | #include "nouveau_gpio.h" | ||
30 | 31 | ||
31 | #include <linux/io-mapping.h> | 32 | #include <linux/io-mapping.h> |
32 | 33 | ||
@@ -3124,49 +3125,6 @@ init_8d(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) | |||
3124 | return 1; | 3125 | return 1; |
3125 | } | 3126 | } |
3126 | 3127 | ||
3127 | static void | ||
3128 | init_gpio_unknv50(struct nvbios *bios, struct dcb_gpio_entry *gpio) | ||
3129 | { | ||
3130 | const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c }; | ||
3131 | u32 r, s, v; | ||
3132 | |||
3133 | /* Not a clue, needs de-magicing */ | ||
3134 | r = nv50_gpio_ctl[gpio->line >> 4]; | ||
3135 | s = (gpio->line & 0x0f); | ||
3136 | v = bios_rd32(bios, r) & ~(0x00010001 << s); | ||
3137 | switch ((gpio->entry & 0x06000000) >> 25) { | ||
3138 | case 1: | ||
3139 | v |= (0x00000001 << s); | ||
3140 | break; | ||
3141 | case 2: | ||
3142 | v |= (0x00010000 << s); | ||
3143 | break; | ||
3144 | default: | ||
3145 | break; | ||
3146 | } | ||
3147 | |||
3148 | bios_wr32(bios, r, v); | ||
3149 | } | ||
3150 | |||
3151 | static void | ||
3152 | init_gpio_unknvd0(struct nvbios *bios, struct dcb_gpio_entry *gpio) | ||
3153 | { | ||
3154 | u32 v, i; | ||
3155 | |||
3156 | v = bios_rd32(bios, 0x00d610 + (gpio->line * 4)); | ||
3157 | v &= 0xffffff00; | ||
3158 | v |= (gpio->entry & 0x00ff0000) >> 16; | ||
3159 | bios_wr32(bios, 0x00d610 + (gpio->line * 4), v); | ||
3160 | |||
3161 | i = (gpio->entry & 0x1f000000) >> 24; | ||
3162 | if (i) { | ||
3163 | v = bios_rd32(bios, 0x00d640 + ((i - 1) * 4)); | ||
3164 | v &= 0xffffff00; | ||
3165 | v |= gpio->line; | ||
3166 | bios_wr32(bios, 0x00d640 + ((i - 1) * 4), v); | ||
3167 | } | ||
3168 | } | ||
3169 | |||
3170 | static int | 3128 | static int |
3171 | init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) | 3129 | init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) |
3172 | { | 3130 | { |
@@ -3179,35 +3137,8 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) | |||
3179 | * each GPIO according to various values listed in each entry | 3137 | * each GPIO according to various values listed in each entry |
3180 | */ | 3138 | */ |
3181 | 3139 | ||
3182 | struct drm_nouveau_private *dev_priv = bios->dev->dev_private; | 3140 | if (iexec->execute && bios->execute) |
3183 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | 3141 | nouveau_gpio_reset(bios->dev); |
3184 | int i; | ||
3185 | |||
3186 | if (dev_priv->card_type < NV_50) { | ||
3187 | NV_ERROR(bios->dev, "INIT_GPIO on unsupported chipset\n"); | ||
3188 | return 1; | ||
3189 | } | ||
3190 | |||
3191 | if (!iexec->execute) | ||
3192 | return 1; | ||
3193 | |||
3194 | for (i = 0; i < bios->dcb.gpio.entries; i++) { | ||
3195 | struct dcb_gpio_entry *gpio = &bios->dcb.gpio.entry[i]; | ||
3196 | |||
3197 | BIOSLOG(bios, "0x%04X: Entry: 0x%08X\n", offset, gpio->entry); | ||
3198 | |||
3199 | BIOSLOG(bios, "0x%04X: set gpio 0x%02x, state %d\n", | ||
3200 | offset, gpio->tag, gpio->state_default); | ||
3201 | |||
3202 | if (!bios->execute) | ||
3203 | continue; | ||
3204 | |||
3205 | pgpio->set(bios->dev, gpio->tag, gpio->state_default); | ||
3206 | if (dev_priv->card_type < NV_D0) | ||
3207 | init_gpio_unknv50(bios, gpio); | ||
3208 | else | ||
3209 | init_gpio_unknvd0(bios, gpio); | ||
3210 | } | ||
3211 | 3142 | ||
3212 | return 1; | 3143 | return 1; |
3213 | } | 3144 | } |
@@ -5643,132 +5574,6 @@ static uint16_t findstr(uint8_t *data, int n, const uint8_t *str, int len) | |||
5643 | return 0; | 5574 | return 0; |
5644 | } | 5575 | } |
5645 | 5576 | ||
5646 | static struct dcb_gpio_entry * | ||
5647 | new_gpio_entry(struct nvbios *bios) | ||
5648 | { | ||
5649 | struct drm_device *dev = bios->dev; | ||
5650 | struct dcb_gpio_table *gpio = &bios->dcb.gpio; | ||
5651 | |||
5652 | if (gpio->entries >= DCB_MAX_NUM_GPIO_ENTRIES) { | ||
5653 | NV_ERROR(dev, "exceeded maximum number of gpio entries!!\n"); | ||
5654 | return NULL; | ||
5655 | } | ||
5656 | |||
5657 | return &gpio->entry[gpio->entries++]; | ||
5658 | } | ||
5659 | |||
5660 | struct dcb_gpio_entry * | ||
5661 | nouveau_bios_gpio_entry(struct drm_device *dev, enum dcb_gpio_tag tag) | ||
5662 | { | ||
5663 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
5664 | struct nvbios *bios = &dev_priv->vbios; | ||
5665 | int i; | ||
5666 | |||
5667 | for (i = 0; i < bios->dcb.gpio.entries; i++) { | ||
5668 | if (bios->dcb.gpio.entry[i].tag != tag) | ||
5669 | continue; | ||
5670 | |||
5671 | return &bios->dcb.gpio.entry[i]; | ||
5672 | } | ||
5673 | |||
5674 | return NULL; | ||
5675 | } | ||
5676 | |||
5677 | static void | ||
5678 | parse_dcb_gpio_table(struct nvbios *bios) | ||
5679 | { | ||
5680 | struct drm_device *dev = bios->dev; | ||
5681 | struct dcb_gpio_entry *e; | ||
5682 | u8 headerlen, entries, recordlen; | ||
5683 | u8 *dcb, *gpio = NULL, *entry; | ||
5684 | int i; | ||
5685 | |||
5686 | dcb = ROMPTR(dev, bios->data[0x36]); | ||
5687 | if (dcb[0] >= 0x30) { | ||
5688 | gpio = ROMPTR(dev, dcb[10]); | ||
5689 | if (!gpio) | ||
5690 | goto no_table; | ||
5691 | |||
5692 | headerlen = gpio[1]; | ||
5693 | entries = gpio[2]; | ||
5694 | recordlen = gpio[3]; | ||
5695 | } else | ||
5696 | if (dcb[0] >= 0x22 && dcb[-1] >= 0x13) { | ||
5697 | gpio = ROMPTR(dev, dcb[-15]); | ||
5698 | if (!gpio) | ||
5699 | goto no_table; | ||
5700 | |||
5701 | headerlen = 3; | ||
5702 | entries = gpio[2]; | ||
5703 | recordlen = gpio[1]; | ||
5704 | } else | ||
5705 | if (dcb[0] >= 0x22) { | ||
5706 | /* No GPIO table present, parse the TVDAC GPIO data. */ | ||
5707 | uint8_t *tvdac_gpio = &dcb[-5]; | ||
5708 | |||
5709 | if (tvdac_gpio[0] & 1) { | ||
5710 | e = new_gpio_entry(bios); | ||
5711 | e->tag = DCB_GPIO_TVDAC0; | ||
5712 | e->line = tvdac_gpio[1] >> 4; | ||
5713 | e->state[0] = !!(tvdac_gpio[0] & 2); | ||
5714 | e->state[1] = !e->state[0]; | ||
5715 | } | ||
5716 | |||
5717 | goto no_table; | ||
5718 | } else { | ||
5719 | NV_DEBUG(dev, "no/unknown gpio table on DCB 0x%02x\n", dcb[0]); | ||
5720 | goto no_table; | ||
5721 | } | ||
5722 | |||
5723 | entry = gpio + headerlen; | ||
5724 | for (i = 0; i < entries; i++, entry += recordlen) { | ||
5725 | e = new_gpio_entry(bios); | ||
5726 | if (!e) | ||
5727 | break; | ||
5728 | |||
5729 | if (gpio[0] < 0x40) { | ||
5730 | e->entry = ROM16(entry[0]); | ||
5731 | e->tag = (e->entry & 0x07e0) >> 5; | ||
5732 | if (e->tag == 0x3f) { | ||
5733 | bios->dcb.gpio.entries--; | ||
5734 | continue; | ||
5735 | } | ||
5736 | |||
5737 | e->line = (e->entry & 0x001f); | ||
5738 | e->state[0] = ((e->entry & 0xf800) >> 11) != 4; | ||
5739 | e->state[1] = !e->state[0]; | ||
5740 | } else { | ||
5741 | e->entry = ROM32(entry[0]); | ||
5742 | e->tag = (e->entry & 0x0000ff00) >> 8; | ||
5743 | if (e->tag == 0xff) { | ||
5744 | bios->dcb.gpio.entries--; | ||
5745 | continue; | ||
5746 | } | ||
5747 | |||
5748 | e->line = (e->entry & 0x0000001f) >> 0; | ||
5749 | if (gpio[0] == 0x40) { | ||
5750 | e->state_default = (e->entry & 0x01000000) >> 24; | ||
5751 | e->state[0] = (e->entry & 0x18000000) >> 27; | ||
5752 | e->state[1] = (e->entry & 0x60000000) >> 29; | ||
5753 | } else { | ||
5754 | e->state_default = (e->entry & 0x00000080) >> 7; | ||
5755 | e->state[0] = (entry[4] >> 4) & 3; | ||
5756 | e->state[1] = (entry[4] >> 6) & 3; | ||
5757 | } | ||
5758 | } | ||
5759 | } | ||
5760 | |||
5761 | no_table: | ||
5762 | /* Apple iMac G4 NV18 */ | ||
5763 | if (nv_match_device(dev, 0x0189, 0x10de, 0x0010)) { | ||
5764 | e = new_gpio_entry(bios); | ||
5765 | if (e) { | ||
5766 | e->tag = DCB_GPIO_TVDAC0; | ||
5767 | e->line = 4; | ||
5768 | } | ||
5769 | } | ||
5770 | } | ||
5771 | |||
5772 | void * | 5577 | void * |
5773 | dcb_table(struct drm_device *dev) | 5578 | dcb_table(struct drm_device *dev) |
5774 | { | 5579 | { |
@@ -6366,9 +6171,6 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios) | |||
6366 | NV_TRACE(dev, "DCB version %d.%d\n", dcbt[0] >> 4, dcbt[0] & 0xf); | 6171 | NV_TRACE(dev, "DCB version %d.%d\n", dcbt[0] >> 4, dcbt[0] & 0xf); |
6367 | 6172 | ||
6368 | dcb->version = dcbt[0]; | 6173 | dcb->version = dcbt[0]; |
6369 | if (dcb->version >= 0x30) | ||
6370 | dcb->gpio_table_ptr = ROM16(dcbt[10]); | ||
6371 | |||
6372 | dcb_outp_foreach(dev, NULL, parse_dcb_entry); | 6174 | dcb_outp_foreach(dev, NULL, parse_dcb_entry); |
6373 | 6175 | ||
6374 | /* | 6176 | /* |
@@ -6393,8 +6195,6 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios) | |||
6393 | } | 6195 | } |
6394 | } | 6196 | } |
6395 | dcb_fake_connectors(bios); | 6197 | dcb_fake_connectors(bios); |
6396 | |||
6397 | parse_dcb_gpio_table(bios); | ||
6398 | return 0; | 6198 | return 0; |
6399 | } | 6199 | } |
6400 | 6200 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h index 32b911d38e9a..1e382ad5a2b8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.h +++ b/drivers/gpu/drm/nouveau/nouveau_bios.h | |||
@@ -61,19 +61,6 @@ enum dcb_gpio_tag { | |||
61 | DCB_GPIO_UNUSED = 0xff | 61 | DCB_GPIO_UNUSED = 0xff |
62 | }; | 62 | }; |
63 | 63 | ||
64 | struct dcb_gpio_entry { | ||
65 | enum dcb_gpio_tag tag; | ||
66 | int line; | ||
67 | uint32_t entry; | ||
68 | uint8_t state_default; | ||
69 | uint8_t state[2]; | ||
70 | }; | ||
71 | |||
72 | struct dcb_gpio_table { | ||
73 | int entries; | ||
74 | struct dcb_gpio_entry entry[DCB_MAX_NUM_GPIO_ENTRIES]; | ||
75 | }; | ||
76 | |||
77 | enum dcb_connector_type { | 64 | enum dcb_connector_type { |
78 | DCB_CONNECTOR_VGA = 0x00, | 65 | DCB_CONNECTOR_VGA = 0x00, |
79 | DCB_CONNECTOR_TV_0 = 0x10, | 66 | DCB_CONNECTOR_TV_0 = 0x10, |
@@ -142,12 +129,8 @@ struct dcb_entry { | |||
142 | 129 | ||
143 | struct dcb_table { | 130 | struct dcb_table { |
144 | uint8_t version; | 131 | uint8_t version; |
145 | |||
146 | int entries; | 132 | int entries; |
147 | struct dcb_entry entry[DCB_MAX_NUM_ENTRIES]; | 133 | struct dcb_entry entry[DCB_MAX_NUM_ENTRIES]; |
148 | |||
149 | uint16_t gpio_table_ptr; | ||
150 | struct dcb_gpio_table gpio; | ||
151 | }; | 134 | }; |
152 | 135 | ||
153 | enum nouveau_or { | 136 | enum nouveau_or { |
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index df99c7f1191a..f3ce34be082a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include "nouveau_encoder.h" | 35 | #include "nouveau_encoder.h" |
36 | #include "nouveau_crtc.h" | 36 | #include "nouveau_crtc.h" |
37 | #include "nouveau_connector.h" | 37 | #include "nouveau_connector.h" |
38 | #include "nouveau_gpio.h" | ||
38 | #include "nouveau_hw.h" | 39 | #include "nouveau_hw.h" |
39 | 40 | ||
40 | static void nouveau_connector_hotplug(void *, int); | 41 | static void nouveau_connector_hotplug(void *, int); |
@@ -83,7 +84,6 @@ nouveau_connector_destroy(struct drm_connector *connector) | |||
83 | { | 84 | { |
84 | struct nouveau_connector *nv_connector = nouveau_connector(connector); | 85 | struct nouveau_connector *nv_connector = nouveau_connector(connector); |
85 | struct drm_nouveau_private *dev_priv; | 86 | struct drm_nouveau_private *dev_priv; |
86 | struct nouveau_gpio_engine *pgpio; | ||
87 | struct drm_device *dev; | 87 | struct drm_device *dev; |
88 | 88 | ||
89 | if (!nv_connector) | 89 | if (!nv_connector) |
@@ -93,10 +93,9 @@ nouveau_connector_destroy(struct drm_connector *connector) | |||
93 | dev_priv = dev->dev_private; | 93 | dev_priv = dev->dev_private; |
94 | NV_DEBUG_KMS(dev, "\n"); | 94 | NV_DEBUG_KMS(dev, "\n"); |
95 | 95 | ||
96 | pgpio = &dev_priv->engine.gpio; | 96 | if (nv_connector->hpd != DCB_GPIO_UNUSED) { |
97 | if (pgpio->irq_unregister) { | 97 | nouveau_gpio_isr_del(dev, 0, nv_connector->hpd, 0xff, |
98 | pgpio->irq_unregister(dev, nv_connector->hpd, | 98 | nouveau_connector_hotplug, connector); |
99 | nouveau_connector_hotplug, connector); | ||
100 | } | 99 | } |
101 | 100 | ||
102 | kfree(nv_connector->edid); | 101 | kfree(nv_connector->edid); |
@@ -876,7 +875,6 @@ nouveau_connector_create(struct drm_device *dev, int index) | |||
876 | const struct drm_connector_funcs *funcs = &nouveau_connector_funcs; | 875 | const struct drm_connector_funcs *funcs = &nouveau_connector_funcs; |
877 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 876 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
878 | struct nouveau_display_engine *disp = &dev_priv->engine.display; | 877 | struct nouveau_display_engine *disp = &dev_priv->engine.display; |
879 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | ||
880 | struct nouveau_connector *nv_connector = NULL; | 878 | struct nouveau_connector *nv_connector = NULL; |
881 | struct drm_connector *connector; | 879 | struct drm_connector *connector; |
882 | int type, ret = 0; | 880 | int type, ret = 0; |
@@ -1050,13 +1048,13 @@ nouveau_connector_create(struct drm_device *dev, int index) | |||
1050 | break; | 1048 | break; |
1051 | } | 1049 | } |
1052 | 1050 | ||
1053 | if (nv_connector->hpd != DCB_GPIO_UNUSED && pgpio->irq_register) { | 1051 | connector->polled = DRM_CONNECTOR_POLL_CONNECT; |
1054 | pgpio->irq_register(dev, nv_connector->hpd, | 1052 | if (nv_connector->hpd != DCB_GPIO_UNUSED) { |
1055 | nouveau_connector_hotplug, connector); | 1053 | ret = nouveau_gpio_isr_add(dev, 0, nv_connector->hpd, 0xff, |
1056 | 1054 | nouveau_connector_hotplug, | |
1057 | connector->polled = DRM_CONNECTOR_POLL_HPD; | 1055 | connector); |
1058 | } else { | 1056 | if (ret == 0) |
1059 | connector->polled = DRM_CONNECTOR_POLL_CONNECT; | 1057 | connector->polled = DRM_CONNECTOR_POLL_HPD; |
1060 | } | 1058 | } |
1061 | 1059 | ||
1062 | drm_sysfs_connector_add(connector); | 1060 | drm_sysfs_connector_add(connector); |
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 02b00c827da3..9b93b703ceab 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include "nouveau_connector.h" | 29 | #include "nouveau_connector.h" |
30 | #include "nouveau_encoder.h" | 30 | #include "nouveau_encoder.h" |
31 | #include "nouveau_crtc.h" | 31 | #include "nouveau_crtc.h" |
32 | #include "nouveau_gpio.h" | ||
32 | 33 | ||
33 | /****************************************************************************** | 34 | /****************************************************************************** |
34 | * aux channel util functions | 35 | * aux channel util functions |
@@ -556,8 +557,6 @@ dp_link_train_eq(struct drm_device *dev, struct dp_state *dp) | |||
556 | bool | 557 | bool |
557 | nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate) | 558 | nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate) |
558 | { | 559 | { |
559 | struct drm_nouveau_private *dev_priv = encoder->dev->dev_private; | ||
560 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | ||
561 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | 560 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); |
562 | struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); | 561 | struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); |
563 | struct nouveau_connector *nv_connector = | 562 | struct nouveau_connector *nv_connector = |
@@ -587,7 +586,7 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate) | |||
587 | * we take during link training (DP_SET_POWER is one), we need | 586 | * we take during link training (DP_SET_POWER is one), we need |
588 | * to ignore them for the moment to avoid races. | 587 | * to ignore them for the moment to avoid races. |
589 | */ | 588 | */ |
590 | pgpio->irq_enable(dev, nv_connector->hpd, false); | 589 | nouveau_gpio_irq(dev, 0, nv_connector->hpd, 0xff, false); |
591 | 590 | ||
592 | /* enable down-spreading, if possible */ | 591 | /* enable down-spreading, if possible */ |
593 | if (dp.table[1] >= 16) { | 592 | if (dp.table[1] >= 16) { |
@@ -636,7 +635,7 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate) | |||
636 | nouveau_bios_run_init_table(dev, ROM16(dp.entry[8]), dp.dcb, dp.crtc); | 635 | nouveau_bios_run_init_table(dev, ROM16(dp.entry[8]), dp.dcb, dp.crtc); |
637 | 636 | ||
638 | /* re-enable hotplug detect */ | 637 | /* re-enable hotplug detect */ |
639 | pgpio->irq_enable(dev, nv_connector->hpd, true); | 638 | nouveau_gpio_irq(dev, 0, nv_connector->hpd, 0xff, true); |
640 | return true; | 639 | return true; |
641 | } | 640 | } |
642 | 641 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 909b991416ed..0af525820347 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h | |||
@@ -408,19 +408,13 @@ struct nouveau_display_engine { | |||
408 | }; | 408 | }; |
409 | 409 | ||
410 | struct nouveau_gpio_engine { | 410 | struct nouveau_gpio_engine { |
411 | void *priv; | 411 | spinlock_t lock; |
412 | 412 | struct list_head isr; | |
413 | int (*init)(struct drm_device *); | 413 | int (*init)(struct drm_device *); |
414 | void (*takedown)(struct drm_device *); | 414 | void (*fini)(struct drm_device *); |
415 | 415 | int (*drive)(struct drm_device *, int line, int dir, int out); | |
416 | int (*get)(struct drm_device *, enum dcb_gpio_tag); | 416 | int (*sense)(struct drm_device *, int line); |
417 | int (*set)(struct drm_device *, enum dcb_gpio_tag, int state); | 417 | void (*irq_enable)(struct drm_device *, int line, bool); |
418 | |||
419 | int (*irq_register)(struct drm_device *, enum dcb_gpio_tag, | ||
420 | void (*)(void *, int), void *); | ||
421 | void (*irq_unregister)(struct drm_device *, enum dcb_gpio_tag, | ||
422 | void (*)(void *, int), void *); | ||
423 | bool (*irq_enable)(struct drm_device *, enum dcb_gpio_tag, bool on); | ||
424 | }; | 418 | }; |
425 | 419 | ||
426 | struct nouveau_pm_voltage_level { | 420 | struct nouveau_pm_voltage_level { |
@@ -1091,8 +1085,6 @@ extern int nouveau_run_vbios_init(struct drm_device *); | |||
1091 | extern void nouveau_bios_run_init_table(struct drm_device *, uint16_t table, | 1085 | extern void nouveau_bios_run_init_table(struct drm_device *, uint16_t table, |
1092 | struct dcb_entry *, int crtc); | 1086 | struct dcb_entry *, int crtc); |
1093 | extern void nouveau_bios_init_exec(struct drm_device *, uint16_t table); | 1087 | extern void nouveau_bios_init_exec(struct drm_device *, uint16_t table); |
1094 | extern struct dcb_gpio_entry *nouveau_bios_gpio_entry(struct drm_device *, | ||
1095 | enum dcb_gpio_tag); | ||
1096 | extern struct dcb_connector_table_entry * | 1088 | extern struct dcb_connector_table_entry * |
1097 | nouveau_bios_connector_entry(struct drm_device *, int index); | 1089 | nouveau_bios_connector_entry(struct drm_device *, int index); |
1098 | extern u32 get_pll_register(struct drm_device *, enum pll_types); | 1090 | extern u32 get_pll_register(struct drm_device *, enum pll_types); |
@@ -1476,23 +1468,22 @@ int nouveau_display_dumb_destroy(struct drm_file *, struct drm_device *, | |||
1476 | uint32_t handle); | 1468 | uint32_t handle); |
1477 | 1469 | ||
1478 | /* nv10_gpio.c */ | 1470 | /* nv10_gpio.c */ |
1479 | int nv10_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); | 1471 | int nv10_gpio_init(struct drm_device *dev); |
1480 | int nv10_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); | 1472 | void nv10_gpio_fini(struct drm_device *dev); |
1473 | int nv10_gpio_drive(struct drm_device *dev, int line, int dir, int out); | ||
1474 | int nv10_gpio_sense(struct drm_device *dev, int line); | ||
1475 | void nv10_gpio_irq_enable(struct drm_device *, int line, bool on); | ||
1481 | 1476 | ||
1482 | /* nv50_gpio.c */ | 1477 | /* nv50_gpio.c */ |
1483 | int nv50_gpio_init(struct drm_device *dev); | 1478 | int nv50_gpio_init(struct drm_device *dev); |
1484 | void nv50_gpio_fini(struct drm_device *dev); | 1479 | void nv50_gpio_fini(struct drm_device *dev); |
1485 | int nv50_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); | 1480 | int nv50_gpio_drive(struct drm_device *dev, int line, int dir, int out); |
1486 | int nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); | 1481 | int nv50_gpio_sense(struct drm_device *dev, int line); |
1487 | int nvd0_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); | 1482 | void nv50_gpio_irq_enable(struct drm_device *, int line, bool on); |
1488 | int nvd0_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); | 1483 | int nvd0_gpio_drive(struct drm_device *dev, int line, int dir, int out); |
1489 | int nv50_gpio_irq_register(struct drm_device *, enum dcb_gpio_tag, | 1484 | int nvd0_gpio_sense(struct drm_device *dev, int line); |
1490 | void (*)(void *, int), void *); | 1485 | |
1491 | void nv50_gpio_irq_unregister(struct drm_device *, enum dcb_gpio_tag, | 1486 | /* nv50_calc.c */ |
1492 | void (*)(void *, int), void *); | ||
1493 | bool nv50_gpio_irq_enable(struct drm_device *, enum dcb_gpio_tag, bool on); | ||
1494 | |||
1495 | /* nv50_calc. */ | ||
1496 | int nv50_calc_pll(struct drm_device *, struct pll_lims *, int clk, | 1487 | int nv50_calc_pll(struct drm_device *, struct pll_lims *, int clk, |
1497 | int *N1, int *M1, int *N2, int *M2, int *P); | 1488 | int *N1, int *M1, int *N2, int *M2, int *P); |
1498 | int nva3_calc_pll(struct drm_device *, struct pll_lims *, | 1489 | int nva3_calc_pll(struct drm_device *, struct pll_lims *, |
diff --git a/drivers/gpu/drm/nouveau/nouveau_gpio.c b/drivers/gpu/drm/nouveau/nouveau_gpio.c new file mode 100644 index 000000000000..a580cc62337a --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_gpio.c | |||
@@ -0,0 +1,400 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Red Hat Inc. | ||
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: Ben Skeggs | ||
23 | */ | ||
24 | |||
25 | #include "drmP.h" | ||
26 | #include "nouveau_drv.h" | ||
27 | #include "nouveau_i2c.h" | ||
28 | #include "nouveau_gpio.h" | ||
29 | |||
30 | static u8 * | ||
31 | dcb_gpio_table(struct drm_device *dev) | ||
32 | { | ||
33 | u8 *dcb = dcb_table(dev); | ||
34 | if (dcb) { | ||
35 | if (dcb[0] >= 0x30 && dcb[1] >= 0x0c) | ||
36 | return ROMPTR(dev, dcb[0x0a]); | ||
37 | if (dcb[0] >= 0x22 && dcb[-1] >= 0x13) | ||
38 | return ROMPTR(dev, dcb[-15]); | ||
39 | } | ||
40 | return NULL; | ||
41 | } | ||
42 | |||
43 | static u8 * | ||
44 | dcb_gpio_entry(struct drm_device *dev, int idx, int ent, u8 *version) | ||
45 | { | ||
46 | u8 *table = dcb_gpio_table(dev); | ||
47 | if (table) { | ||
48 | *version = table[0]; | ||
49 | if (*version < 0x30 && ent < table[2]) | ||
50 | return table + 3 + (ent * table[1]); | ||
51 | else if (ent < table[2]) | ||
52 | return table + table[1] + (ent * table[3]); | ||
53 | } | ||
54 | return NULL; | ||
55 | } | ||
56 | |||
57 | int | ||
58 | nouveau_gpio_drive(struct drm_device *dev, int idx, int line, int dir, int out) | ||
59 | { | ||
60 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
61 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | ||
62 | |||
63 | return pgpio->drive ? pgpio->drive(dev, line, dir, out) : -ENODEV; | ||
64 | } | ||
65 | |||
66 | int | ||
67 | nouveau_gpio_sense(struct drm_device *dev, int idx, int line) | ||
68 | { | ||
69 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
70 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | ||
71 | |||
72 | return pgpio->sense ? pgpio->sense(dev, line) : -ENODEV; | ||
73 | } | ||
74 | |||
75 | int | ||
76 | nouveau_gpio_find(struct drm_device *dev, int idx, u8 func, u8 line, | ||
77 | struct gpio_func *gpio) | ||
78 | { | ||
79 | u8 *table, *entry, version; | ||
80 | int i = -1; | ||
81 | |||
82 | if (line == 0xff && func == 0xff) | ||
83 | return -EINVAL; | ||
84 | |||
85 | while ((entry = dcb_gpio_entry(dev, idx, ++i, &version))) { | ||
86 | if (version < 0x40) { | ||
87 | u16 data = ROM16(entry[0]); | ||
88 | *gpio = (struct gpio_func) { | ||
89 | .line = (data & 0x001f) >> 0, | ||
90 | .func = (data & 0x07e0) >> 5, | ||
91 | .log[0] = (data & 0x1800) >> 11, | ||
92 | .log[1] = (data & 0x6000) >> 13, | ||
93 | }; | ||
94 | } else | ||
95 | if (version < 0x41) { | ||
96 | *gpio = (struct gpio_func) { | ||
97 | .line = entry[0] & 0x1f, | ||
98 | .func = entry[1], | ||
99 | .log[0] = (entry[3] & 0x18) >> 3, | ||
100 | .log[1] = (entry[3] & 0x60) >> 5, | ||
101 | }; | ||
102 | } else { | ||
103 | *gpio = (struct gpio_func) { | ||
104 | .line = entry[0] & 0x3f, | ||
105 | .func = entry[1], | ||
106 | .log[0] = (entry[4] & 0x30) >> 4, | ||
107 | .log[1] = (entry[4] & 0xc0) >> 6, | ||
108 | }; | ||
109 | } | ||
110 | |||
111 | if ((line == 0xff || line == gpio->line) && | ||
112 | (func == 0xff || func == gpio->func)) | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | /* DCB 2.2, fixed TVDAC GPIO data */ | ||
117 | if ((table = dcb_table(dev)) && table[0] >= 0x22) { | ||
118 | if (func == DCB_GPIO_TVDAC0) { | ||
119 | *gpio = (struct gpio_func) { | ||
120 | .func = DCB_GPIO_TVDAC0, | ||
121 | .line = table[-4] >> 4, | ||
122 | .log[0] = !!(table[-5] & 2), | ||
123 | .log[1] = !(table[-5] & 2), | ||
124 | }; | ||
125 | return 0; | ||
126 | } | ||
127 | } | ||
128 | |||
129 | /* Apple iMac G4 NV18 */ | ||
130 | if (nv_match_device(dev, 0x0189, 0x10de, 0x0010)) { | ||
131 | if (func == DCB_GPIO_TVDAC0) { | ||
132 | *gpio = (struct gpio_func) { | ||
133 | .func = DCB_GPIO_TVDAC0, | ||
134 | .line = 4, | ||
135 | .log[0] = 0, | ||
136 | .log[1] = 1, | ||
137 | }; | ||
138 | return 0; | ||
139 | } | ||
140 | } | ||
141 | |||
142 | return -EINVAL; | ||
143 | } | ||
144 | |||
145 | int | ||
146 | nouveau_gpio_set(struct drm_device *dev, int idx, u8 tag, u8 line, int state) | ||
147 | { | ||
148 | struct gpio_func gpio; | ||
149 | int ret; | ||
150 | |||
151 | ret = nouveau_gpio_find(dev, idx, tag, line, &gpio); | ||
152 | if (ret == 0) { | ||
153 | int dir = !!(gpio.log[state] & 0x02); | ||
154 | int out = !!(gpio.log[state] & 0x01); | ||
155 | ret = nouveau_gpio_drive(dev, idx, gpio.line, dir, out); | ||
156 | } | ||
157 | |||
158 | return ret; | ||
159 | } | ||
160 | |||
161 | int | ||
162 | nouveau_gpio_get(struct drm_device *dev, int idx, u8 tag, u8 line) | ||
163 | { | ||
164 | struct gpio_func gpio; | ||
165 | int ret; | ||
166 | |||
167 | ret = nouveau_gpio_find(dev, idx, tag, line, &gpio); | ||
168 | if (ret == 0) { | ||
169 | ret = nouveau_gpio_sense(dev, idx, gpio.line); | ||
170 | if (ret >= 0) | ||
171 | ret = (ret == (gpio.log[1] & 1)); | ||
172 | } | ||
173 | |||
174 | return ret; | ||
175 | } | ||
176 | |||
177 | int | ||
178 | nouveau_gpio_irq(struct drm_device *dev, int idx, u8 tag, u8 line, bool on) | ||
179 | { | ||
180 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
181 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | ||
182 | struct gpio_func gpio; | ||
183 | int ret; | ||
184 | |||
185 | ret = nouveau_gpio_find(dev, idx, tag, line, &gpio); | ||
186 | if (ret == 0) { | ||
187 | if (idx == 0 && pgpio->irq_enable) | ||
188 | pgpio->irq_enable(dev, gpio.line, on); | ||
189 | else | ||
190 | ret = -ENODEV; | ||
191 | } | ||
192 | |||
193 | return ret; | ||
194 | } | ||
195 | |||
196 | struct gpio_isr { | ||
197 | struct drm_device *dev; | ||
198 | struct list_head head; | ||
199 | struct work_struct work; | ||
200 | int idx; | ||
201 | struct gpio_func func; | ||
202 | void (*handler)(void *, int); | ||
203 | void *data; | ||
204 | bool inhibit; | ||
205 | }; | ||
206 | |||
207 | static void | ||
208 | nouveau_gpio_isr_bh(struct work_struct *work) | ||
209 | { | ||
210 | struct gpio_isr *isr = container_of(work, struct gpio_isr, work); | ||
211 | struct drm_device *dev = isr->dev; | ||
212 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
213 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | ||
214 | unsigned long flags; | ||
215 | int state; | ||
216 | |||
217 | state = nouveau_gpio_get(dev, isr->idx, isr->func.func, isr->func.line); | ||
218 | if (state >= 0) | ||
219 | isr->handler(isr->data, state); | ||
220 | |||
221 | spin_lock_irqsave(&pgpio->lock, flags); | ||
222 | isr->inhibit = false; | ||
223 | spin_unlock_irqrestore(&pgpio->lock, flags); | ||
224 | } | ||
225 | |||
226 | void | ||
227 | nouveau_gpio_isr(struct drm_device *dev, int idx, u32 line_mask) | ||
228 | { | ||
229 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
230 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | ||
231 | struct gpio_isr *isr; | ||
232 | |||
233 | if (idx != 0) | ||
234 | return; | ||
235 | |||
236 | spin_lock(&pgpio->lock); | ||
237 | list_for_each_entry(isr, &pgpio->isr, head) { | ||
238 | if (line_mask & (1 << isr->func.line)) { | ||
239 | if (isr->inhibit) | ||
240 | continue; | ||
241 | isr->inhibit = true; | ||
242 | schedule_work(&isr->work); | ||
243 | } | ||
244 | } | ||
245 | spin_unlock(&pgpio->lock); | ||
246 | } | ||
247 | |||
248 | int | ||
249 | nouveau_gpio_isr_add(struct drm_device *dev, int idx, u8 tag, u8 line, | ||
250 | void (*handler)(void *, int), void *data) | ||
251 | { | ||
252 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
253 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | ||
254 | struct gpio_isr *isr; | ||
255 | unsigned long flags; | ||
256 | int ret; | ||
257 | |||
258 | isr = kzalloc(sizeof(*isr), GFP_KERNEL); | ||
259 | if (!isr) | ||
260 | return -ENOMEM; | ||
261 | |||
262 | ret = nouveau_gpio_find(dev, idx, tag, line, &isr->func); | ||
263 | if (ret) { | ||
264 | kfree(isr); | ||
265 | return ret; | ||
266 | } | ||
267 | |||
268 | INIT_WORK(&isr->work, nouveau_gpio_isr_bh); | ||
269 | isr->dev = dev; | ||
270 | isr->handler = handler; | ||
271 | isr->data = data; | ||
272 | isr->idx = idx; | ||
273 | |||
274 | spin_lock_irqsave(&pgpio->lock, flags); | ||
275 | list_add(&isr->head, &pgpio->isr); | ||
276 | spin_unlock_irqrestore(&pgpio->lock, flags); | ||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | void | ||
281 | nouveau_gpio_isr_del(struct drm_device *dev, int idx, u8 tag, u8 line, | ||
282 | void (*handler)(void *, int), void *data) | ||
283 | { | ||
284 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
285 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | ||
286 | struct gpio_isr *isr, *tmp; | ||
287 | struct gpio_func func; | ||
288 | unsigned long flags; | ||
289 | LIST_HEAD(tofree); | ||
290 | int ret; | ||
291 | |||
292 | ret = nouveau_gpio_find(dev, idx, tag, line, &func); | ||
293 | if (ret == 0) { | ||
294 | spin_lock_irqsave(&pgpio->lock, flags); | ||
295 | list_for_each_entry_safe(isr, tmp, &pgpio->isr, head) { | ||
296 | if (memcmp(&isr->func, &func, sizeof(func)) || | ||
297 | isr->idx != idx || | ||
298 | isr->handler != handler || isr->data != data) | ||
299 | continue; | ||
300 | list_move(&isr->head, &tofree); | ||
301 | } | ||
302 | spin_unlock_irqrestore(&pgpio->lock, flags); | ||
303 | |||
304 | list_for_each_entry_safe(isr, tmp, &tofree, head) { | ||
305 | flush_work_sync(&isr->work); | ||
306 | kfree(isr); | ||
307 | } | ||
308 | } | ||
309 | } | ||
310 | |||
311 | int | ||
312 | nouveau_gpio_create(struct drm_device *dev) | ||
313 | { | ||
314 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
315 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | ||
316 | |||
317 | INIT_LIST_HEAD(&pgpio->isr); | ||
318 | spin_lock_init(&pgpio->lock); | ||
319 | |||
320 | return nouveau_gpio_init(dev); | ||
321 | } | ||
322 | |||
323 | void | ||
324 | nouveau_gpio_destroy(struct drm_device *dev) | ||
325 | { | ||
326 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
327 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | ||
328 | |||
329 | nouveau_gpio_fini(dev); | ||
330 | BUG_ON(!list_empty(&pgpio->isr)); | ||
331 | } | ||
332 | |||
333 | int | ||
334 | nouveau_gpio_init(struct drm_device *dev) | ||
335 | { | ||
336 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
337 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | ||
338 | int ret = 0; | ||
339 | |||
340 | if (pgpio->init) | ||
341 | ret = pgpio->init(dev); | ||
342 | |||
343 | return ret; | ||
344 | } | ||
345 | |||
346 | void | ||
347 | nouveau_gpio_fini(struct drm_device *dev) | ||
348 | { | ||
349 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
350 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | ||
351 | |||
352 | if (pgpio->fini) | ||
353 | pgpio->fini(dev); | ||
354 | } | ||
355 | |||
356 | void | ||
357 | nouveau_gpio_reset(struct drm_device *dev) | ||
358 | { | ||
359 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
360 | u8 *entry, version; | ||
361 | int ent = -1; | ||
362 | |||
363 | while ((entry = dcb_gpio_entry(dev, 0, ++ent, &version))) { | ||
364 | u8 func = 0xff, line, defs, unk0, unk1; | ||
365 | if (version >= 0x41) { | ||
366 | defs = !!(entry[0] & 0x80); | ||
367 | line = entry[0] & 0x3f; | ||
368 | func = entry[1]; | ||
369 | unk0 = entry[2]; | ||
370 | unk1 = entry[3] & 0x1f; | ||
371 | } else | ||
372 | if (version >= 0x40) { | ||
373 | line = entry[0] & 0x1f; | ||
374 | func = entry[1]; | ||
375 | defs = !!(entry[3] & 0x01); | ||
376 | unk0 = !!(entry[3] & 0x02); | ||
377 | unk1 = !!(entry[3] & 0x04); | ||
378 | } else { | ||
379 | break; | ||
380 | } | ||
381 | |||
382 | if (func == 0xff) | ||
383 | continue; | ||
384 | |||
385 | nouveau_gpio_func_set(dev, func, defs); | ||
386 | |||
387 | if (dev_priv->card_type >= NV_D0) { | ||
388 | nv_mask(dev, 0x00d610 + (line * 4), 0xff, unk0); | ||
389 | if (unk1--) | ||
390 | nv_mask(dev, 0x00d640 + (unk1 * 4), 0xff, line); | ||
391 | } else | ||
392 | if (dev_priv->card_type >= NV_50) { | ||
393 | static const u32 regs[] = { 0xe100, 0xe28c }; | ||
394 | u32 val = (unk1 << 16) | unk0; | ||
395 | u32 reg = regs[line >> 4]; line &= 0x0f; | ||
396 | |||
397 | nv_mask(dev, reg, 0x00010001 << line, val << line); | ||
398 | } | ||
399 | } | ||
400 | } | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_gpio.h b/drivers/gpu/drm/nouveau/nouveau_gpio.h new file mode 100644 index 000000000000..64c5cb077ace --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_gpio.h | |||
@@ -0,0 +1,71 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Red Hat Inc. | ||
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 | |||
23 | #ifndef __NOUVEAU_GPIO_H__ | ||
24 | #define __NOUVEAU_GPIO_H__ | ||
25 | |||
26 | struct gpio_func { | ||
27 | u8 func; | ||
28 | u8 line; | ||
29 | u8 log[2]; | ||
30 | }; | ||
31 | |||
32 | /* nouveau_gpio.c */ | ||
33 | int nouveau_gpio_create(struct drm_device *); | ||
34 | void nouveau_gpio_destroy(struct drm_device *); | ||
35 | int nouveau_gpio_init(struct drm_device *); | ||
36 | void nouveau_gpio_fini(struct drm_device *); | ||
37 | void nouveau_gpio_reset(struct drm_device *); | ||
38 | int nouveau_gpio_drive(struct drm_device *, int idx, int line, | ||
39 | int dir, int out); | ||
40 | int nouveau_gpio_sense(struct drm_device *, int idx, int line); | ||
41 | int nouveau_gpio_find(struct drm_device *, int idx, u8 tag, u8 line, | ||
42 | struct gpio_func *); | ||
43 | int nouveau_gpio_set(struct drm_device *, int idx, u8 tag, u8 line, int state); | ||
44 | int nouveau_gpio_get(struct drm_device *, int idx, u8 tag, u8 line); | ||
45 | int nouveau_gpio_irq(struct drm_device *, int idx, u8 tag, u8 line, bool on); | ||
46 | void nouveau_gpio_isr(struct drm_device *, int idx, u32 mask); | ||
47 | int nouveau_gpio_isr_add(struct drm_device *, int idx, u8 tag, u8 line, | ||
48 | void (*)(void *, int state), void *data); | ||
49 | void nouveau_gpio_isr_del(struct drm_device *, int idx, u8 tag, u8 line, | ||
50 | void (*)(void *, int state), void *data); | ||
51 | |||
52 | static inline bool | ||
53 | nouveau_gpio_func_valid(struct drm_device *dev, u8 tag) | ||
54 | { | ||
55 | struct gpio_func func; | ||
56 | return (nouveau_gpio_find(dev, 0, tag, 0xff, &func)) == 0; | ||
57 | } | ||
58 | |||
59 | static inline int | ||
60 | nouveau_gpio_func_set(struct drm_device *dev, u8 tag, int state) | ||
61 | { | ||
62 | return nouveau_gpio_set(dev, 0, tag, 0xff, state); | ||
63 | } | ||
64 | |||
65 | static inline int | ||
66 | nouveau_gpio_func_get(struct drm_device *dev, u8 tag) | ||
67 | { | ||
68 | return nouveau_gpio_get(dev, 0, tag, 0xff); | ||
69 | } | ||
70 | |||
71 | #endif | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index 788ba33da77c..aba3362d421a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c | |||
@@ -26,6 +26,7 @@ | |||
26 | 26 | ||
27 | #include "nouveau_drv.h" | 27 | #include "nouveau_drv.h" |
28 | #include "nouveau_pm.h" | 28 | #include "nouveau_pm.h" |
29 | #include "nouveau_gpio.h" | ||
29 | 30 | ||
30 | #ifdef CONFIG_ACPI | 31 | #ifdef CONFIG_ACPI |
31 | #include <linux/acpi.h> | 32 | #include <linux/acpi.h> |
@@ -38,27 +39,25 @@ static int | |||
38 | nouveau_pwmfan_get(struct drm_device *dev) | 39 | nouveau_pwmfan_get(struct drm_device *dev) |
39 | { | 40 | { |
40 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 41 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
41 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | ||
42 | struct nouveau_pm_engine *pm = &dev_priv->engine.pm; | 42 | struct nouveau_pm_engine *pm = &dev_priv->engine.pm; |
43 | struct dcb_gpio_entry *gpio = NULL; | 43 | struct gpio_func gpio; |
44 | u32 divs, duty; | 44 | u32 divs, duty; |
45 | int ret; | 45 | int ret; |
46 | 46 | ||
47 | if (!pm->pwm_get) | 47 | if (!pm->pwm_get) |
48 | return -ENODEV; | 48 | return -ENODEV; |
49 | 49 | ||
50 | gpio = nouveau_bios_gpio_entry(dev, DCB_GPIO_PWM_FAN); | 50 | ret = nouveau_gpio_find(dev, 0, DCB_GPIO_PWM_FAN, 0xff, &gpio); |
51 | if (gpio) { | 51 | if (ret == 0) { |
52 | ret = pm->pwm_get(dev, gpio->line, &divs, &duty); | 52 | ret = pm->pwm_get(dev, gpio.line, &divs, &duty); |
53 | if (ret == 0) { | 53 | if (ret == 0) { |
54 | divs = max(divs, duty); | 54 | divs = max(divs, duty); |
55 | if (dev_priv->card_type <= NV_40 || | 55 | if (dev_priv->card_type <= NV_40 || (gpio.log[0] & 1)) |
56 | (gpio->state[0] & 1)) | ||
57 | duty = divs - duty; | 56 | duty = divs - duty; |
58 | return (duty * 100) / divs; | 57 | return (duty * 100) / divs; |
59 | } | 58 | } |
60 | 59 | ||
61 | return pgpio->get(dev, gpio->tag) * 100; | 60 | return nouveau_gpio_func_get(dev, gpio.func) * 100; |
62 | } | 61 | } |
63 | 62 | ||
64 | return -ENODEV; | 63 | return -ENODEV; |
@@ -69,14 +68,15 @@ nouveau_pwmfan_set(struct drm_device *dev, int percent) | |||
69 | { | 68 | { |
70 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 69 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
71 | struct nouveau_pm_engine *pm = &dev_priv->engine.pm; | 70 | struct nouveau_pm_engine *pm = &dev_priv->engine.pm; |
72 | struct dcb_gpio_entry *gpio; | 71 | struct gpio_func gpio; |
73 | u32 divs, duty; | 72 | u32 divs, duty; |
73 | int ret; | ||
74 | 74 | ||
75 | if (!pm->pwm_set) | 75 | if (!pm->pwm_set) |
76 | return -ENODEV; | 76 | return -ENODEV; |
77 | 77 | ||
78 | gpio = nouveau_bios_gpio_entry(dev, DCB_GPIO_PWM_FAN); | 78 | ret = nouveau_gpio_find(dev, 0, DCB_GPIO_PWM_FAN, 0xff, &gpio); |
79 | if (gpio) { | 79 | if (ret == 0) { |
80 | divs = pm->pwm_divisor; | 80 | divs = pm->pwm_divisor; |
81 | if (pm->fan.pwm_freq) { | 81 | if (pm->fan.pwm_freq) { |
82 | /*XXX: PNVIO clock more than likely... */ | 82 | /*XXX: PNVIO clock more than likely... */ |
@@ -86,11 +86,10 @@ nouveau_pwmfan_set(struct drm_device *dev, int percent) | |||
86 | } | 86 | } |
87 | 87 | ||
88 | duty = ((divs * percent) + 99) / 100; | 88 | duty = ((divs * percent) + 99) / 100; |
89 | if (dev_priv->card_type <= NV_40 || | 89 | if (dev_priv->card_type <= NV_40 || (gpio.log[0] & 1)) |
90 | (gpio->state[0] & 1)) | ||
91 | duty = divs - duty; | 90 | duty = divs - duty; |
92 | 91 | ||
93 | return pm->pwm_set(dev, gpio->line, divs, duty); | 92 | return pm->pwm_set(dev, gpio.line, divs, duty); |
94 | } | 93 | } |
95 | 94 | ||
96 | return -ENODEV; | 95 | return -ENODEV; |
@@ -472,24 +471,24 @@ nouveau_hwmon_show_fan0_input(struct device *d, struct device_attribute *attr, | |||
472 | struct drm_device *dev = dev_get_drvdata(d); | 471 | struct drm_device *dev = dev_get_drvdata(d); |
473 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 472 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
474 | struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; | 473 | struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; |
475 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | 474 | struct gpio_func gpio; |
476 | struct dcb_gpio_entry *gpio; | ||
477 | u32 cycles, cur, prev; | 475 | u32 cycles, cur, prev; |
478 | u64 start; | 476 | u64 start; |
477 | int ret; | ||
479 | 478 | ||
480 | gpio = nouveau_bios_gpio_entry(dev, DCB_GPIO_FAN_SENSE); | 479 | ret = nouveau_gpio_find(dev, 0, DCB_GPIO_FAN_SENSE, 0xff, &gpio); |
481 | if (!gpio) | 480 | if (ret) |
482 | return -ENODEV; | 481 | return ret; |
483 | 482 | ||
484 | /* Monitor the GPIO input 0x3b for 250ms. | 483 | /* Monitor the GPIO input 0x3b for 250ms. |
485 | * When the fan spins, it changes the value of GPIO FAN_SENSE. | 484 | * When the fan spins, it changes the value of GPIO FAN_SENSE. |
486 | * We get 4 changes (0 -> 1 -> 0 -> 1 -> [...]) per complete rotation. | 485 | * We get 4 changes (0 -> 1 -> 0 -> 1 -> [...]) per complete rotation. |
487 | */ | 486 | */ |
488 | start = ptimer->read(dev); | 487 | start = ptimer->read(dev); |
489 | prev = pgpio->get(dev, DCB_GPIO_FAN_SENSE); | 488 | prev = nouveau_gpio_sense(dev, 0, gpio.line); |
490 | cycles = 0; | 489 | cycles = 0; |
491 | do { | 490 | do { |
492 | cur = pgpio->get(dev, DCB_GPIO_FAN_SENSE); | 491 | cur = nouveau_gpio_sense(dev, 0, gpio.line); |
493 | if (prev != cur) { | 492 | if (prev != cur) { |
494 | cycles++; | 493 | cycles++; |
495 | prev = cur; | 494 | prev = cur; |
@@ -701,7 +700,7 @@ nouveau_hwmon_init(struct drm_device *dev) | |||
701 | } | 700 | } |
702 | 701 | ||
703 | /* if the card can read the fan rpm */ | 702 | /* if the card can read the fan rpm */ |
704 | if (nouveau_bios_gpio_entry(dev, DCB_GPIO_FAN_SENSE)) { | 703 | if (nouveau_gpio_func_valid(dev, DCB_GPIO_FAN_SENSE)) { |
705 | ret = sysfs_create_group(&dev->pdev->dev.kobj, | 704 | ret = sysfs_create_group(&dev->pdev->dev.kobj, |
706 | &hwmon_fan_rpm_attrgroup); | 705 | &hwmon_fan_rpm_attrgroup); |
707 | if (ret) | 706 | if (ret) |
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 5d8ad4ec3ac1..c4edba6a457d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include "nouveau_drm.h" | 36 | #include "nouveau_drm.h" |
37 | #include "nouveau_fbcon.h" | 37 | #include "nouveau_fbcon.h" |
38 | #include "nouveau_ramht.h" | 38 | #include "nouveau_ramht.h" |
39 | #include "nouveau_gpio.h" | ||
39 | #include "nouveau_pm.h" | 40 | #include "nouveau_pm.h" |
40 | #include "nv50_display.h" | 41 | #include "nv50_display.h" |
41 | 42 | ||
@@ -83,11 +84,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) | |||
83 | engine->display.destroy = nv04_display_destroy; | 84 | engine->display.destroy = nv04_display_destroy; |
84 | engine->display.init = nv04_display_init; | 85 | engine->display.init = nv04_display_init; |
85 | engine->display.fini = nv04_display_fini; | 86 | engine->display.fini = nv04_display_fini; |
86 | engine->gpio.init = nouveau_stub_init; | ||
87 | engine->gpio.takedown = nouveau_stub_takedown; | ||
88 | engine->gpio.get = NULL; | ||
89 | engine->gpio.set = NULL; | ||
90 | engine->gpio.irq_enable = NULL; | ||
91 | engine->pm.clocks_get = nv04_pm_clocks_get; | 87 | engine->pm.clocks_get = nv04_pm_clocks_get; |
92 | engine->pm.clocks_pre = nv04_pm_clocks_pre; | 88 | engine->pm.clocks_pre = nv04_pm_clocks_pre; |
93 | engine->pm.clocks_set = nv04_pm_clocks_set; | 89 | engine->pm.clocks_set = nv04_pm_clocks_set; |
@@ -133,11 +129,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) | |||
133 | engine->display.destroy = nv04_display_destroy; | 129 | engine->display.destroy = nv04_display_destroy; |
134 | engine->display.init = nv04_display_init; | 130 | engine->display.init = nv04_display_init; |
135 | engine->display.fini = nv04_display_fini; | 131 | engine->display.fini = nv04_display_fini; |
136 | engine->gpio.init = nouveau_stub_init; | 132 | engine->gpio.drive = nv10_gpio_drive; |
137 | engine->gpio.takedown = nouveau_stub_takedown; | 133 | engine->gpio.sense = nv10_gpio_sense; |
138 | engine->gpio.get = nv10_gpio_get; | ||
139 | engine->gpio.set = nv10_gpio_set; | ||
140 | engine->gpio.irq_enable = NULL; | ||
141 | engine->pm.clocks_get = nv04_pm_clocks_get; | 134 | engine->pm.clocks_get = nv04_pm_clocks_get; |
142 | engine->pm.clocks_pre = nv04_pm_clocks_pre; | 135 | engine->pm.clocks_pre = nv04_pm_clocks_pre; |
143 | engine->pm.clocks_set = nv04_pm_clocks_set; | 136 | engine->pm.clocks_set = nv04_pm_clocks_set; |
@@ -183,11 +176,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) | |||
183 | engine->display.destroy = nv04_display_destroy; | 176 | engine->display.destroy = nv04_display_destroy; |
184 | engine->display.init = nv04_display_init; | 177 | engine->display.init = nv04_display_init; |
185 | engine->display.fini = nv04_display_fini; | 178 | engine->display.fini = nv04_display_fini; |
186 | engine->gpio.init = nouveau_stub_init; | 179 | engine->gpio.drive = nv10_gpio_drive; |
187 | engine->gpio.takedown = nouveau_stub_takedown; | 180 | engine->gpio.sense = nv10_gpio_sense; |
188 | engine->gpio.get = nv10_gpio_get; | ||
189 | engine->gpio.set = nv10_gpio_set; | ||
190 | engine->gpio.irq_enable = NULL; | ||
191 | engine->pm.clocks_get = nv04_pm_clocks_get; | 181 | engine->pm.clocks_get = nv04_pm_clocks_get; |
192 | engine->pm.clocks_pre = nv04_pm_clocks_pre; | 182 | engine->pm.clocks_pre = nv04_pm_clocks_pre; |
193 | engine->pm.clocks_set = nv04_pm_clocks_set; | 183 | engine->pm.clocks_set = nv04_pm_clocks_set; |
@@ -233,11 +223,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) | |||
233 | engine->display.destroy = nv04_display_destroy; | 223 | engine->display.destroy = nv04_display_destroy; |
234 | engine->display.init = nv04_display_init; | 224 | engine->display.init = nv04_display_init; |
235 | engine->display.fini = nv04_display_fini; | 225 | engine->display.fini = nv04_display_fini; |
236 | engine->gpio.init = nouveau_stub_init; | 226 | engine->gpio.drive = nv10_gpio_drive; |
237 | engine->gpio.takedown = nouveau_stub_takedown; | 227 | engine->gpio.sense = nv10_gpio_sense; |
238 | engine->gpio.get = nv10_gpio_get; | ||
239 | engine->gpio.set = nv10_gpio_set; | ||
240 | engine->gpio.irq_enable = NULL; | ||
241 | engine->pm.clocks_get = nv04_pm_clocks_get; | 228 | engine->pm.clocks_get = nv04_pm_clocks_get; |
242 | engine->pm.clocks_pre = nv04_pm_clocks_pre; | 229 | engine->pm.clocks_pre = nv04_pm_clocks_pre; |
243 | engine->pm.clocks_set = nv04_pm_clocks_set; | 230 | engine->pm.clocks_set = nv04_pm_clocks_set; |
@@ -286,11 +273,8 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) | |||
286 | engine->display.destroy = nv04_display_destroy; | 273 | engine->display.destroy = nv04_display_destroy; |
287 | engine->display.init = nv04_display_init; | 274 | engine->display.init = nv04_display_init; |
288 | engine->display.fini = nv04_display_fini; | 275 | engine->display.fini = nv04_display_fini; |
289 | engine->gpio.init = nouveau_stub_init; | 276 | engine->gpio.drive = nv10_gpio_drive; |
290 | engine->gpio.takedown = nouveau_stub_takedown; | 277 | engine->gpio.sense = nv10_gpio_sense; |
291 | engine->gpio.get = nv10_gpio_get; | ||
292 | engine->gpio.set = nv10_gpio_set; | ||
293 | engine->gpio.irq_enable = NULL; | ||
294 | engine->pm.clocks_get = nv40_pm_clocks_get; | 278 | engine->pm.clocks_get = nv40_pm_clocks_get; |
295 | engine->pm.clocks_pre = nv40_pm_clocks_pre; | 279 | engine->pm.clocks_pre = nv40_pm_clocks_pre; |
296 | engine->pm.clocks_set = nv40_pm_clocks_set; | 280 | engine->pm.clocks_set = nv40_pm_clocks_set; |
@@ -345,11 +329,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) | |||
345 | engine->display.init = nv50_display_init; | 329 | engine->display.init = nv50_display_init; |
346 | engine->display.fini = nv50_display_fini; | 330 | engine->display.fini = nv50_display_fini; |
347 | engine->gpio.init = nv50_gpio_init; | 331 | engine->gpio.init = nv50_gpio_init; |
348 | engine->gpio.takedown = nv50_gpio_fini; | 332 | engine->gpio.fini = nv50_gpio_fini; |
349 | engine->gpio.get = nv50_gpio_get; | 333 | engine->gpio.drive = nv50_gpio_drive; |
350 | engine->gpio.set = nv50_gpio_set; | 334 | engine->gpio.sense = nv50_gpio_sense; |
351 | engine->gpio.irq_register = nv50_gpio_irq_register; | ||
352 | engine->gpio.irq_unregister = nv50_gpio_irq_unregister; | ||
353 | engine->gpio.irq_enable = nv50_gpio_irq_enable; | 335 | engine->gpio.irq_enable = nv50_gpio_irq_enable; |
354 | switch (dev_priv->chipset) { | 336 | switch (dev_priv->chipset) { |
355 | case 0x84: | 337 | case 0x84: |
@@ -421,11 +403,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) | |||
421 | engine->display.init = nv50_display_init; | 403 | engine->display.init = nv50_display_init; |
422 | engine->display.fini = nv50_display_fini; | 404 | engine->display.fini = nv50_display_fini; |
423 | engine->gpio.init = nv50_gpio_init; | 405 | engine->gpio.init = nv50_gpio_init; |
424 | engine->gpio.takedown = nouveau_stub_takedown; | 406 | engine->gpio.fini = nv50_gpio_fini; |
425 | engine->gpio.get = nv50_gpio_get; | 407 | engine->gpio.drive = nv50_gpio_drive; |
426 | engine->gpio.set = nv50_gpio_set; | 408 | engine->gpio.sense = nv50_gpio_sense; |
427 | engine->gpio.irq_register = nv50_gpio_irq_register; | ||
428 | engine->gpio.irq_unregister = nv50_gpio_irq_unregister; | ||
429 | engine->gpio.irq_enable = nv50_gpio_irq_enable; | 409 | engine->gpio.irq_enable = nv50_gpio_irq_enable; |
430 | engine->vram.init = nvc0_vram_init; | 410 | engine->vram.init = nvc0_vram_init; |
431 | engine->vram.takedown = nv50_vram_fini; | 411 | engine->vram.takedown = nv50_vram_fini; |
@@ -474,11 +454,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) | |||
474 | engine->display.init = nvd0_display_init; | 454 | engine->display.init = nvd0_display_init; |
475 | engine->display.fini = nvd0_display_fini; | 455 | engine->display.fini = nvd0_display_fini; |
476 | engine->gpio.init = nv50_gpio_init; | 456 | engine->gpio.init = nv50_gpio_init; |
477 | engine->gpio.takedown = nouveau_stub_takedown; | 457 | engine->gpio.fini = nv50_gpio_fini; |
478 | engine->gpio.get = nvd0_gpio_get; | 458 | engine->gpio.drive = nvd0_gpio_drive; |
479 | engine->gpio.set = nvd0_gpio_set; | 459 | engine->gpio.sense = nvd0_gpio_sense; |
480 | engine->gpio.irq_register = nv50_gpio_irq_register; | ||
481 | engine->gpio.irq_unregister = nv50_gpio_irq_unregister; | ||
482 | engine->gpio.irq_enable = nv50_gpio_irq_enable; | 460 | engine->gpio.irq_enable = nv50_gpio_irq_enable; |
483 | engine->vram.init = nvc0_vram_init; | 461 | engine->vram.init = nvc0_vram_init; |
484 | engine->vram.takedown = nv50_vram_fini; | 462 | engine->vram.takedown = nv50_vram_fini; |
@@ -630,7 +608,7 @@ nouveau_card_init(struct drm_device *dev) | |||
630 | goto out_gart; | 608 | goto out_gart; |
631 | 609 | ||
632 | /* PGPIO */ | 610 | /* PGPIO */ |
633 | ret = engine->gpio.init(dev); | 611 | ret = nouveau_gpio_create(dev); |
634 | if (ret) | 612 | if (ret) |
635 | goto out_mc; | 613 | goto out_mc; |
636 | 614 | ||
@@ -798,7 +776,7 @@ out_engine: | |||
798 | out_timer: | 776 | out_timer: |
799 | engine->timer.takedown(dev); | 777 | engine->timer.takedown(dev); |
800 | out_gpio: | 778 | out_gpio: |
801 | engine->gpio.takedown(dev); | 779 | nouveau_gpio_destroy(dev); |
802 | out_mc: | 780 | out_mc: |
803 | engine->mc.takedown(dev); | 781 | engine->mc.takedown(dev); |
804 | out_gart: | 782 | out_gart: |
@@ -851,7 +829,7 @@ static void nouveau_card_takedown(struct drm_device *dev) | |||
851 | } | 829 | } |
852 | engine->fb.takedown(dev); | 830 | engine->fb.takedown(dev); |
853 | engine->timer.takedown(dev); | 831 | engine->timer.takedown(dev); |
854 | engine->gpio.takedown(dev); | 832 | nouveau_gpio_destroy(dev); |
855 | engine->mc.takedown(dev); | 833 | engine->mc.takedown(dev); |
856 | engine->display.late_takedown(dev); | 834 | engine->display.late_takedown(dev); |
857 | 835 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_volt.c b/drivers/gpu/drm/nouveau/nouveau_volt.c index ac15b46ea3a0..b010cb997b34 100644 --- a/drivers/gpu/drm/nouveau/nouveau_volt.c +++ b/drivers/gpu/drm/nouveau/nouveau_volt.c | |||
@@ -26,6 +26,7 @@ | |||
26 | 26 | ||
27 | #include "nouveau_drv.h" | 27 | #include "nouveau_drv.h" |
28 | #include "nouveau_pm.h" | 28 | #include "nouveau_pm.h" |
29 | #include "nouveau_gpio.h" | ||
29 | 30 | ||
30 | static const enum dcb_gpio_tag vidtag[] = { 0x04, 0x05, 0x06, 0x1a, 0x73 }; | 31 | static const enum dcb_gpio_tag vidtag[] = { 0x04, 0x05, 0x06, 0x1a, 0x73 }; |
31 | static int nr_vidtag = sizeof(vidtag) / sizeof(vidtag[0]); | 32 | static int nr_vidtag = sizeof(vidtag) / sizeof(vidtag[0]); |
@@ -34,7 +35,6 @@ int | |||
34 | nouveau_voltage_gpio_get(struct drm_device *dev) | 35 | nouveau_voltage_gpio_get(struct drm_device *dev) |
35 | { | 36 | { |
36 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 37 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
37 | struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio; | ||
38 | struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage; | 38 | struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage; |
39 | u8 vid = 0; | 39 | u8 vid = 0; |
40 | int i; | 40 | int i; |
@@ -43,7 +43,7 @@ nouveau_voltage_gpio_get(struct drm_device *dev) | |||
43 | if (!(volt->vid_mask & (1 << i))) | 43 | if (!(volt->vid_mask & (1 << i))) |
44 | continue; | 44 | continue; |
45 | 45 | ||
46 | vid |= gpio->get(dev, vidtag[i]) << i; | 46 | vid |= nouveau_gpio_func_get(dev, vidtag[i]) << i; |
47 | } | 47 | } |
48 | 48 | ||
49 | return nouveau_volt_lvl_lookup(dev, vid); | 49 | return nouveau_volt_lvl_lookup(dev, vid); |
@@ -53,7 +53,6 @@ int | |||
53 | nouveau_voltage_gpio_set(struct drm_device *dev, int voltage) | 53 | nouveau_voltage_gpio_set(struct drm_device *dev, int voltage) |
54 | { | 54 | { |
55 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 55 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
56 | struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio; | ||
57 | struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage; | 56 | struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage; |
58 | int vid, i; | 57 | int vid, i; |
59 | 58 | ||
@@ -65,7 +64,7 @@ nouveau_voltage_gpio_set(struct drm_device *dev, int voltage) | |||
65 | if (!(volt->vid_mask & (1 << i))) | 64 | if (!(volt->vid_mask & (1 << i))) |
66 | continue; | 65 | continue; |
67 | 66 | ||
68 | gpio->set(dev, vidtag[i], !!(vid & (1 << i))); | 67 | nouveau_gpio_func_set(dev, vidtag[i], !!(vid & (1 << i))); |
69 | } | 68 | } |
70 | 69 | ||
71 | return 0; | 70 | return 0; |
@@ -194,7 +193,7 @@ nouveau_volt_init(struct drm_device *dev) | |||
194 | return; | 193 | return; |
195 | } | 194 | } |
196 | 195 | ||
197 | if (!nouveau_bios_gpio_entry(dev, vidtag[i])) { | 196 | if (!nouveau_gpio_func_valid(dev, vidtag[i])) { |
198 | NV_DEBUG(dev, "vid bit %d has no gpio tag\n", i); | 197 | NV_DEBUG(dev, "vid bit %d has no gpio tag\n", i); |
199 | return; | 198 | return; |
200 | } | 199 | } |
diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c index e000455e06d0..8300266ffaea 100644 --- a/drivers/gpu/drm/nouveau/nv04_dac.c +++ b/drivers/gpu/drm/nouveau/nv04_dac.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include "nouveau_connector.h" | 32 | #include "nouveau_connector.h" |
33 | #include "nouveau_crtc.h" | 33 | #include "nouveau_crtc.h" |
34 | #include "nouveau_hw.h" | 34 | #include "nouveau_hw.h" |
35 | #include "nouveau_gpio.h" | ||
35 | #include "nvreg.h" | 36 | #include "nvreg.h" |
36 | 37 | ||
37 | int nv04_dac_output_offset(struct drm_encoder *encoder) | 38 | int nv04_dac_output_offset(struct drm_encoder *encoder) |
@@ -220,7 +221,6 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) | |||
220 | { | 221 | { |
221 | struct drm_device *dev = encoder->dev; | 222 | struct drm_device *dev = encoder->dev; |
222 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 223 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
223 | struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio; | ||
224 | struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; | 224 | struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; |
225 | uint32_t sample, testval, regoffset = nv04_dac_output_offset(encoder); | 225 | uint32_t sample, testval, regoffset = nv04_dac_output_offset(encoder); |
226 | uint32_t saved_powerctrl_2 = 0, saved_powerctrl_4 = 0, saved_routput, | 226 | uint32_t saved_powerctrl_2 = 0, saved_powerctrl_4 = 0, saved_routput, |
@@ -252,11 +252,11 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) | |||
252 | nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4 & 0xffffffcf); | 252 | nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4 & 0xffffffcf); |
253 | } | 253 | } |
254 | 254 | ||
255 | saved_gpio1 = gpio->get(dev, DCB_GPIO_TVDAC1); | 255 | saved_gpio1 = nouveau_gpio_func_get(dev, DCB_GPIO_TVDAC1); |
256 | saved_gpio0 = gpio->get(dev, DCB_GPIO_TVDAC0); | 256 | saved_gpio0 = nouveau_gpio_func_get(dev, DCB_GPIO_TVDAC0); |
257 | 257 | ||
258 | gpio->set(dev, DCB_GPIO_TVDAC1, dcb->type == OUTPUT_TV); | 258 | nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC1, dcb->type == OUTPUT_TV); |
259 | gpio->set(dev, DCB_GPIO_TVDAC0, dcb->type == OUTPUT_TV); | 259 | nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC0, dcb->type == OUTPUT_TV); |
260 | 260 | ||
261 | msleep(4); | 261 | msleep(4); |
262 | 262 | ||
@@ -306,8 +306,8 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) | |||
306 | nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4); | 306 | nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4); |
307 | nvWriteMC(dev, NV_PBUS_POWERCTRL_2, saved_powerctrl_2); | 307 | nvWriteMC(dev, NV_PBUS_POWERCTRL_2, saved_powerctrl_2); |
308 | 308 | ||
309 | gpio->set(dev, DCB_GPIO_TVDAC1, saved_gpio1); | 309 | nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC1, saved_gpio1); |
310 | gpio->set(dev, DCB_GPIO_TVDAC0, saved_gpio0); | 310 | nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC0, saved_gpio0); |
311 | 311 | ||
312 | return sample; | 312 | return sample; |
313 | } | 313 | } |
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 @@ | |||
28 | #include "nouveau_drv.h" | 28 | #include "nouveau_drv.h" |
29 | #include "nouveau_hw.h" | 29 | #include "nouveau_hw.h" |
30 | 30 | ||
31 | static bool | ||
32 | get_gpio_location(struct dcb_gpio_entry *ent, uint32_t *reg, uint32_t *shift, | ||
33 | uint32_t *mask) | ||
34 | { | ||
35 | if (ent->line < 2) { | ||
36 | *reg = NV_PCRTC_GPIO; | ||
37 | *shift = ent->line * 16; | ||
38 | *mask = 0x11; | ||
39 | |||
40 | } else if (ent->line < 10) { | ||
41 | *reg = NV_PCRTC_GPIO_EXT; | ||
42 | *shift = (ent->line - 2) * 4; | ||
43 | *mask = 0x3; | ||
44 | |||
45 | } else if (ent->line < 14) { | ||
46 | *reg = NV_PCRTC_850; | ||
47 | *shift = (ent->line - 10) * 4; | ||
48 | *mask = 0x3; | ||
49 | |||
50 | } else { | ||
51 | return false; | ||
52 | } | ||
53 | |||
54 | return true; | ||
55 | } | ||
56 | |||
57 | int | 31 | int |
58 | nv10_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag) | 32 | nv10_gpio_sense(struct drm_device *dev, int line) |
59 | { | 33 | { |
60 | struct dcb_gpio_entry *ent = nouveau_bios_gpio_entry(dev, tag); | 34 | if (line < 2) { |
61 | uint32_t reg, shift, mask, value; | 35 | line = line * 16; |
62 | 36 | line = NVReadCRTC(dev, 0, NV_PCRTC_GPIO) >> line; | |
63 | if (!ent) | 37 | return !!(line & 0x0100); |
64 | return -ENODEV; | 38 | } else |
65 | 39 | if (line < 10) { | |
66 | if (!get_gpio_location(ent, ®, &shift, &mask)) | 40 | line = (line - 2) * 4; |
67 | return -ENODEV; | 41 | line = NVReadCRTC(dev, 0, NV_PCRTC_GPIO_EXT) >> line; |
68 | 42 | return !!(line & 0x04); | |
69 | value = NVReadCRTC(dev, 0, reg) >> shift; | 43 | } else |
44 | if (line < 14) { | ||
45 | line = (line - 10) * 4; | ||
46 | line = NVReadCRTC(dev, 0, NV_PCRTC_850) >> line; | ||
47 | return !!(line & 0x04); | ||
48 | } | ||
70 | 49 | ||
71 | return (value & 1) == ent->state[1]; | 50 | return -EINVAL; |
72 | } | 51 | } |
73 | 52 | ||
74 | int | 53 | int |
75 | nv10_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state) | 54 | nv10_gpio_drive(struct drm_device *dev, int line, int dir, int out) |
76 | { | 55 | { |
77 | struct dcb_gpio_entry *ent = nouveau_bios_gpio_entry(dev, tag); | 56 | u32 reg, mask, data; |
78 | uint32_t reg, shift, mask, value; | 57 | |
79 | 58 | if (line < 2) { | |
80 | if (!ent) | 59 | line = line * 16; |
81 | return -ENODEV; | 60 | reg = NV_PCRTC_GPIO; |
82 | 61 | mask = 0x00000011; | |
83 | if (!get_gpio_location(ent, ®, &shift, &mask)) | 62 | data = (dir << 4) | out; |
84 | return -ENODEV; | 63 | } else |
85 | 64 | if (line < 10) { | |
86 | value = ent->state[state & 1] << shift; | 65 | line = (line - 2) * 4; |
87 | mask = ~(mask << shift); | 66 | reg = NV_PCRTC_GPIO_EXT; |
88 | 67 | mask = 0x00000003 << ((line - 2) * 4); | |
89 | NVWriteCRTC(dev, 0, reg, value | (NVReadCRTC(dev, 0, reg) & mask)); | 68 | data = (dir << 1) | out; |
69 | } else | ||
70 | if (line < 14) { | ||
71 | line = (line - 10) * 4; | ||
72 | reg = NV_PCRTC_850; | ||
73 | mask = 0x00000003; | ||
74 | data = (dir << 1) | out; | ||
75 | } else { | ||
76 | return -EINVAL; | ||
77 | } | ||
90 | 78 | ||
79 | mask = NVReadCRTC(dev, 0, reg) & ~(mask << line); | ||
80 | NVWriteCRTC(dev, 0, reg, mask | (data << line)); | ||
91 | return 0; | 81 | return 0; |
92 | } | 82 | } |
diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c index 3900cebba560..696d7e7dc2a0 100644 --- a/drivers/gpu/drm/nouveau/nv17_tv.c +++ b/drivers/gpu/drm/nouveau/nv17_tv.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include "nouveau_encoder.h" | 30 | #include "nouveau_encoder.h" |
31 | #include "nouveau_connector.h" | 31 | #include "nouveau_connector.h" |
32 | #include "nouveau_crtc.h" | 32 | #include "nouveau_crtc.h" |
33 | #include "nouveau_gpio.h" | ||
33 | #include "nouveau_hw.h" | 34 | #include "nouveau_hw.h" |
34 | #include "nv17_tv.h" | 35 | #include "nv17_tv.h" |
35 | 36 | ||
@@ -37,7 +38,6 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) | |||
37 | { | 38 | { |
38 | struct drm_device *dev = encoder->dev; | 39 | struct drm_device *dev = encoder->dev; |
39 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 40 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
40 | struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio; | ||
41 | uint32_t testval, regoffset = nv04_dac_output_offset(encoder); | 41 | uint32_t testval, regoffset = nv04_dac_output_offset(encoder); |
42 | uint32_t gpio0, gpio1, fp_htotal, fp_hsync_start, fp_hsync_end, | 42 | uint32_t gpio0, gpio1, fp_htotal, fp_hsync_start, fp_hsync_end, |
43 | fp_control, test_ctrl, dacclk, ctv_14, ctv_1c, ctv_6c; | 43 | fp_control, test_ctrl, dacclk, ctv_14, ctv_1c, ctv_6c; |
@@ -53,8 +53,8 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) | |||
53 | head = (dacclk & 0x100) >> 8; | 53 | head = (dacclk & 0x100) >> 8; |
54 | 54 | ||
55 | /* Save the previous state. */ | 55 | /* Save the previous state. */ |
56 | gpio1 = gpio->get(dev, DCB_GPIO_TVDAC1); | 56 | gpio1 = nouveau_gpio_func_get(dev, DCB_GPIO_TVDAC1); |
57 | gpio0 = gpio->get(dev, DCB_GPIO_TVDAC0); | 57 | gpio0 = nouveau_gpio_func_get(dev, DCB_GPIO_TVDAC0); |
58 | fp_htotal = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL); | 58 | fp_htotal = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL); |
59 | fp_hsync_start = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START); | 59 | fp_hsync_start = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START); |
60 | fp_hsync_end = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END); | 60 | fp_hsync_end = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END); |
@@ -65,8 +65,8 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) | |||
65 | ctv_6c = NVReadRAMDAC(dev, head, 0x680c6c); | 65 | ctv_6c = NVReadRAMDAC(dev, head, 0x680c6c); |
66 | 66 | ||
67 | /* Prepare the DAC for load detection. */ | 67 | /* Prepare the DAC for load detection. */ |
68 | gpio->set(dev, DCB_GPIO_TVDAC1, true); | 68 | nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC1, true); |
69 | gpio->set(dev, DCB_GPIO_TVDAC0, true); | 69 | nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC0, true); |
70 | 70 | ||
71 | NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, 1343); | 71 | NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, 1343); |
72 | NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, 1047); | 72 | NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, 1047); |
@@ -111,8 +111,8 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) | |||
111 | NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END, fp_hsync_end); | 111 | NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END, fp_hsync_end); |
112 | NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, fp_hsync_start); | 112 | NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, fp_hsync_start); |
113 | NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, fp_htotal); | 113 | NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, fp_htotal); |
114 | gpio->set(dev, DCB_GPIO_TVDAC1, gpio1); | 114 | nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC1, gpio1); |
115 | gpio->set(dev, DCB_GPIO_TVDAC0, gpio0); | 115 | nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC0, gpio0); |
116 | 116 | ||
117 | return sample; | 117 | return sample; |
118 | } | 118 | } |
@@ -357,8 +357,6 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder, | |||
357 | static void nv17_tv_dpms(struct drm_encoder *encoder, int mode) | 357 | static void nv17_tv_dpms(struct drm_encoder *encoder, int mode) |
358 | { | 358 | { |
359 | struct drm_device *dev = encoder->dev; | 359 | struct drm_device *dev = encoder->dev; |
360 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
361 | struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio; | ||
362 | struct nv17_tv_state *regs = &to_tv_enc(encoder)->state; | 360 | struct nv17_tv_state *regs = &to_tv_enc(encoder)->state; |
363 | struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder); | 361 | struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder); |
364 | 362 | ||
@@ -383,8 +381,8 @@ static void nv17_tv_dpms(struct drm_encoder *encoder, int mode) | |||
383 | 381 | ||
384 | nv_load_ptv(dev, regs, 200); | 382 | nv_load_ptv(dev, regs, 200); |
385 | 383 | ||
386 | gpio->set(dev, DCB_GPIO_TVDAC1, mode == DRM_MODE_DPMS_ON); | 384 | nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC1, mode == DRM_MODE_DPMS_ON); |
387 | gpio->set(dev, DCB_GPIO_TVDAC0, mode == DRM_MODE_DPMS_ON); | 385 | nouveau_gpio_func_set(dev, DCB_GPIO_TVDAC0, mode == DRM_MODE_DPMS_ON); |
388 | 386 | ||
389 | nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON); | 387 | nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON); |
390 | } | 388 | } |
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 9708b94a0a7b..f408e105a0cd 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include "nouveau_fb.h" | 32 | #include "nouveau_fb.h" |
33 | #include "nouveau_fbcon.h" | 33 | #include "nouveau_fbcon.h" |
34 | #include "nouveau_ramht.h" | 34 | #include "nouveau_ramht.h" |
35 | #include "nouveau_gpio.h" | ||
35 | #include "drm_crtc_helper.h" | 36 | #include "drm_crtc_helper.h" |
36 | 37 | ||
37 | static void nv50_display_isr(struct drm_device *); | 38 | static void nv50_display_isr(struct drm_device *); |
@@ -140,8 +141,6 @@ nv50_display_sync(struct drm_device *dev) | |||
140 | int | 141 | int |
141 | nv50_display_init(struct drm_device *dev) | 142 | nv50_display_init(struct drm_device *dev) |
142 | { | 143 | { |
143 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
144 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | ||
145 | struct drm_connector *connector; | 144 | struct drm_connector *connector; |
146 | struct nouveau_channel *evo; | 145 | struct nouveau_channel *evo; |
147 | int ret, i; | 146 | int ret, i; |
@@ -240,11 +239,7 @@ nv50_display_init(struct drm_device *dev) | |||
240 | /* enable hotplug interrupts */ | 239 | /* enable hotplug interrupts */ |
241 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | 240 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
242 | struct nouveau_connector *conn = nouveau_connector(connector); | 241 | struct nouveau_connector *conn = nouveau_connector(connector); |
243 | 242 | nouveau_gpio_irq(dev, 0, conn->hpd, 0xff, true); | |
244 | if (conn->hpd == DCB_GPIO_UNUSED) | ||
245 | continue; | ||
246 | |||
247 | pgpio->irq_enable(dev, conn->hpd, true); | ||
248 | } | 243 | } |
249 | 244 | ||
250 | ret = nv50_evo_init(dev); | 245 | ret = nv50_evo_init(dev); |
diff --git a/drivers/gpu/drm/nouveau/nv50_gpio.c b/drivers/gpu/drm/nouveau/nv50_gpio.c index 793a5ccca121..f429e6a8ca7a 100644 --- a/drivers/gpu/drm/nouveau/nv50_gpio.c +++ b/drivers/gpu/drm/nouveau/nv50_gpio.c | |||
@@ -25,229 +25,95 @@ | |||
25 | #include "drmP.h" | 25 | #include "drmP.h" |
26 | #include "nouveau_drv.h" | 26 | #include "nouveau_drv.h" |
27 | #include "nouveau_hw.h" | 27 | #include "nouveau_hw.h" |
28 | #include "nouveau_gpio.h" | ||
28 | 29 | ||
29 | #include "nv50_display.h" | 30 | #include "nv50_display.h" |
30 | 31 | ||
31 | static void nv50_gpio_isr(struct drm_device *dev); | ||
32 | static void nv50_gpio_isr_bh(struct work_struct *work); | ||
33 | |||
34 | struct nv50_gpio_priv { | ||
35 | struct list_head handlers; | ||
36 | spinlock_t lock; | ||
37 | }; | ||
38 | |||
39 | struct nv50_gpio_handler { | ||
40 | struct drm_device *dev; | ||
41 | struct list_head head; | ||
42 | struct work_struct work; | ||
43 | bool inhibit; | ||
44 | |||
45 | struct dcb_gpio_entry *gpio; | ||
46 | |||
47 | void (*handler)(void *data, int state); | ||
48 | void *data; | ||
49 | }; | ||
50 | |||
51 | static int | 32 | static int |
52 | nv50_gpio_location(struct dcb_gpio_entry *gpio, uint32_t *reg, uint32_t *shift) | 33 | nv50_gpio_location(int line, u32 *reg, u32 *shift) |
53 | { | 34 | { |
54 | const uint32_t nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 }; | 35 | const uint32_t nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 }; |
55 | 36 | ||
56 | if (gpio->line >= 32) | 37 | if (line >= 32) |
57 | return -EINVAL; | 38 | return -EINVAL; |
58 | 39 | ||
59 | *reg = nv50_gpio_reg[gpio->line >> 3]; | 40 | *reg = nv50_gpio_reg[line >> 3]; |
60 | *shift = (gpio->line & 7) << 2; | 41 | *shift = (line & 7) << 2; |
61 | return 0; | 42 | return 0; |
62 | } | 43 | } |
63 | 44 | ||
64 | int | 45 | int |
65 | nv50_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag) | 46 | nv50_gpio_drive(struct drm_device *dev, int line, int dir, int out) |
66 | { | 47 | { |
67 | struct dcb_gpio_entry *gpio; | 48 | u32 reg, shift; |
68 | uint32_t r, s, v; | ||
69 | |||
70 | gpio = nouveau_bios_gpio_entry(dev, tag); | ||
71 | if (!gpio) | ||
72 | return -ENOENT; | ||
73 | 49 | ||
74 | if (nv50_gpio_location(gpio, &r, &s)) | 50 | if (nv50_gpio_location(line, ®, &shift)) |
75 | return -EINVAL; | 51 | return -EINVAL; |
76 | 52 | ||
77 | v = nv_rd32(dev, r) >> (s + 2); | 53 | nv_mask(dev, reg, 7 << shift, (((dir ^ 1) << 1) | out) << shift); |
78 | return ((v & 1) == (gpio->state[1] & 1)); | 54 | return 0; |
79 | } | 55 | } |
80 | 56 | ||
81 | int | 57 | int |
82 | nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state) | 58 | nv50_gpio_sense(struct drm_device *dev, int line) |
83 | { | 59 | { |
84 | struct dcb_gpio_entry *gpio; | 60 | u32 reg, shift; |
85 | uint32_t r, s, v; | ||
86 | |||
87 | gpio = nouveau_bios_gpio_entry(dev, tag); | ||
88 | if (!gpio) | ||
89 | return -ENOENT; | ||
90 | 61 | ||
91 | if (nv50_gpio_location(gpio, &r, &s)) | 62 | if (nv50_gpio_location(line, ®, &shift)) |
92 | return -EINVAL; | 63 | return -EINVAL; |
93 | 64 | ||
94 | v = nv_rd32(dev, r) & ~(0x3 << s); | 65 | return !!(nv_rd32(dev, reg) & (4 << shift)); |
95 | v |= (gpio->state[state] ^ 2) << s; | ||
96 | nv_wr32(dev, r, v); | ||
97 | return 0; | ||
98 | } | 66 | } |
99 | 67 | ||
100 | int | 68 | void |
101 | nvd0_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag) | 69 | nv50_gpio_irq_enable(struct drm_device *dev, int line, bool on) |
102 | { | 70 | { |
103 | struct dcb_gpio_entry *gpio; | 71 | u32 reg = line < 16 ? 0xe050 : 0xe070; |
104 | u32 v; | 72 | u32 mask = 0x00010001 << (line & 0xf); |
105 | |||
106 | gpio = nouveau_bios_gpio_entry(dev, tag); | ||
107 | if (!gpio) | ||
108 | return -ENOENT; | ||
109 | 73 | ||
110 | v = nv_rd32(dev, 0x00d610 + (gpio->line * 4)); | 74 | nv_wr32(dev, reg + 4, mask); |
111 | v &= 0x00004000; | 75 | nv_mask(dev, reg + 0, mask, on ? mask : 0); |
112 | return (!!v == (gpio->state[1] & 1)); | ||
113 | } | 76 | } |
114 | 77 | ||
115 | int | 78 | int |
116 | nvd0_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state) | 79 | nvd0_gpio_drive(struct drm_device *dev, int line, int dir, int out) |
117 | { | 80 | { |
118 | struct dcb_gpio_entry *gpio; | 81 | u32 data = ((dir ^ 1) << 13) | (out << 12); |
119 | u32 v; | 82 | nv_mask(dev, 0x00d610 + (line * 4), 0x00003000, data); |
120 | 83 | nv_mask(dev, 0x00d604, 0x00000001, 0x00000001); /* update? */ | |
121 | gpio = nouveau_bios_gpio_entry(dev, tag); | ||
122 | if (!gpio) | ||
123 | return -ENOENT; | ||
124 | |||
125 | v = gpio->state[state] ^ 2; | ||
126 | |||
127 | nv_mask(dev, 0x00d610 + (gpio->line * 4), 0x00003000, v << 12); | ||
128 | return 0; | 84 | return 0; |
129 | } | 85 | } |
130 | 86 | ||
131 | int | 87 | int |
132 | nv50_gpio_irq_register(struct drm_device *dev, enum dcb_gpio_tag tag, | 88 | nvd0_gpio_sense(struct drm_device *dev, int line) |
133 | void (*handler)(void *, int), void *data) | ||
134 | { | 89 | { |
135 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 90 | return !!(nv_rd32(dev, 0x00d610 + (line * 4)) & 0x00004000); |
136 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | ||
137 | struct nv50_gpio_priv *priv = pgpio->priv; | ||
138 | struct nv50_gpio_handler *gpioh; | ||
139 | struct dcb_gpio_entry *gpio; | ||
140 | unsigned long flags; | ||
141 | |||
142 | gpio = nouveau_bios_gpio_entry(dev, tag); | ||
143 | if (!gpio) | ||
144 | return -ENOENT; | ||
145 | |||
146 | gpioh = kzalloc(sizeof(*gpioh), GFP_KERNEL); | ||
147 | if (!gpioh) | ||
148 | return -ENOMEM; | ||
149 | |||
150 | INIT_WORK(&gpioh->work, nv50_gpio_isr_bh); | ||
151 | gpioh->dev = dev; | ||
152 | gpioh->gpio = gpio; | ||
153 | gpioh->handler = handler; | ||
154 | gpioh->data = data; | ||
155 | |||
156 | spin_lock_irqsave(&priv->lock, flags); | ||
157 | list_add(&gpioh->head, &priv->handlers); | ||
158 | spin_unlock_irqrestore(&priv->lock, flags); | ||
159 | return 0; | ||
160 | } | 91 | } |
161 | 92 | ||
162 | void | 93 | static void |
163 | nv50_gpio_irq_unregister(struct drm_device *dev, enum dcb_gpio_tag tag, | 94 | nv50_gpio_isr(struct drm_device *dev) |
164 | void (*handler)(void *, int), void *data) | ||
165 | { | ||
166 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
167 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | ||
168 | struct nv50_gpio_priv *priv = pgpio->priv; | ||
169 | struct nv50_gpio_handler *gpioh, *tmp; | ||
170 | struct dcb_gpio_entry *gpio; | ||
171 | LIST_HEAD(tofree); | ||
172 | unsigned long flags; | ||
173 | |||
174 | gpio = nouveau_bios_gpio_entry(dev, tag); | ||
175 | if (!gpio) | ||
176 | return; | ||
177 | |||
178 | spin_lock_irqsave(&priv->lock, flags); | ||
179 | list_for_each_entry_safe(gpioh, tmp, &priv->handlers, head) { | ||
180 | if (gpioh->gpio != gpio || | ||
181 | gpioh->handler != handler || | ||
182 | gpioh->data != data) | ||
183 | continue; | ||
184 | list_move(&gpioh->head, &tofree); | ||
185 | } | ||
186 | spin_unlock_irqrestore(&priv->lock, flags); | ||
187 | |||
188 | list_for_each_entry_safe(gpioh, tmp, &tofree, head) { | ||
189 | flush_work_sync(&gpioh->work); | ||
190 | kfree(gpioh); | ||
191 | } | ||
192 | } | ||
193 | |||
194 | bool | ||
195 | nv50_gpio_irq_enable(struct drm_device *dev, enum dcb_gpio_tag tag, bool on) | ||
196 | { | ||
197 | struct dcb_gpio_entry *gpio; | ||
198 | u32 reg, mask; | ||
199 | |||
200 | gpio = nouveau_bios_gpio_entry(dev, tag); | ||
201 | if (!gpio) | ||
202 | return false; | ||
203 | |||
204 | reg = gpio->line < 16 ? 0xe050 : 0xe070; | ||
205 | mask = 0x00010001 << (gpio->line & 0xf); | ||
206 | |||
207 | nv_wr32(dev, reg + 4, mask); | ||
208 | reg = nv_mask(dev, reg + 0, mask, on ? mask : 0); | ||
209 | return (reg & mask) == mask; | ||
210 | } | ||
211 | |||
212 | static int | ||
213 | nv50_gpio_create(struct drm_device *dev) | ||
214 | { | 95 | { |
215 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 96 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
216 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | 97 | u32 intr0, intr1 = 0; |
217 | struct nv50_gpio_priv *priv; | 98 | u32 hi, lo; |
218 | |||
219 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
220 | if (!priv) | ||
221 | return -ENOMEM; | ||
222 | 99 | ||
223 | INIT_LIST_HEAD(&priv->handlers); | 100 | intr0 = nv_rd32(dev, 0xe054) & nv_rd32(dev, 0xe050); |
224 | spin_lock_init(&priv->lock); | 101 | if (dev_priv->chipset >= 0x90) |
225 | pgpio->priv = priv; | 102 | intr1 = nv_rd32(dev, 0xe074) & nv_rd32(dev, 0xe070); |
226 | return 0; | ||
227 | } | ||
228 | 103 | ||
229 | static void | 104 | hi = (intr0 & 0x0000ffff) | (intr1 << 16); |
230 | nv50_gpio_destroy(struct drm_device *dev) | 105 | lo = (intr0 >> 16) | (intr1 & 0xffff0000); |
231 | { | 106 | nouveau_gpio_isr(dev, 0, hi | lo); |
232 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
233 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | ||
234 | 107 | ||
235 | kfree(pgpio->priv); | 108 | nv_wr32(dev, 0xe054, intr0); |
236 | pgpio->priv = NULL; | 109 | if (dev_priv->chipset >= 0x90) |
110 | nv_wr32(dev, 0xe074, intr1); | ||
237 | } | 111 | } |
238 | 112 | ||
239 | int | 113 | int |
240 | nv50_gpio_init(struct drm_device *dev) | 114 | nv50_gpio_init(struct drm_device *dev) |
241 | { | 115 | { |
242 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 116 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
243 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | ||
244 | int ret; | ||
245 | |||
246 | if (!pgpio->priv) { | ||
247 | ret = nv50_gpio_create(dev); | ||
248 | if (ret) | ||
249 | return ret; | ||
250 | } | ||
251 | 117 | ||
252 | /* disable, and ack any pending gpio interrupts */ | 118 | /* disable, and ack any pending gpio interrupts */ |
253 | nv_wr32(dev, 0xe050, 0x00000000); | 119 | nv_wr32(dev, 0xe050, 0x00000000); |
@@ -270,64 +136,4 @@ nv50_gpio_fini(struct drm_device *dev) | |||
270 | if (dev_priv->chipset >= 0x90) | 136 | if (dev_priv->chipset >= 0x90) |
271 | nv_wr32(dev, 0xe070, 0x00000000); | 137 | nv_wr32(dev, 0xe070, 0x00000000); |
272 | nouveau_irq_unregister(dev, 21); | 138 | nouveau_irq_unregister(dev, 21); |
273 | |||
274 | nv50_gpio_destroy(dev); | ||
275 | } | ||
276 | |||
277 | static void | ||
278 | nv50_gpio_isr_bh(struct work_struct *work) | ||
279 | { | ||
280 | struct nv50_gpio_handler *gpioh = | ||
281 | container_of(work, struct nv50_gpio_handler, work); | ||
282 | struct drm_nouveau_private *dev_priv = gpioh->dev->dev_private; | ||
283 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | ||
284 | struct nv50_gpio_priv *priv = pgpio->priv; | ||
285 | unsigned long flags; | ||
286 | int state; | ||
287 | |||
288 | state = pgpio->get(gpioh->dev, gpioh->gpio->tag); | ||
289 | if (state < 0) | ||
290 | return; | ||
291 | |||
292 | gpioh->handler(gpioh->data, state); | ||
293 | |||
294 | spin_lock_irqsave(&priv->lock, flags); | ||
295 | gpioh->inhibit = false; | ||
296 | spin_unlock_irqrestore(&priv->lock, flags); | ||
297 | } | ||
298 | |||
299 | static void | ||
300 | nv50_gpio_isr(struct drm_device *dev) | ||
301 | { | ||
302 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
303 | struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; | ||
304 | struct nv50_gpio_priv *priv = pgpio->priv; | ||
305 | struct nv50_gpio_handler *gpioh; | ||
306 | u32 intr0, intr1 = 0; | ||
307 | u32 hi, lo, ch; | ||
308 | |||
309 | intr0 = nv_rd32(dev, 0xe054) & nv_rd32(dev, 0xe050); | ||
310 | if (dev_priv->chipset >= 0x90) | ||
311 | intr1 = nv_rd32(dev, 0xe074) & nv_rd32(dev, 0xe070); | ||
312 | |||
313 | hi = (intr0 & 0x0000ffff) | (intr1 << 16); | ||
314 | lo = (intr0 >> 16) | (intr1 & 0xffff0000); | ||
315 | ch = hi | lo; | ||
316 | |||
317 | nv_wr32(dev, 0xe054, intr0); | ||
318 | if (dev_priv->chipset >= 0x90) | ||
319 | nv_wr32(dev, 0xe074, intr1); | ||
320 | |||
321 | spin_lock(&priv->lock); | ||
322 | list_for_each_entry(gpioh, &priv->handlers, head) { | ||
323 | if (!(ch & (1 << gpioh->gpio->line))) | ||
324 | continue; | ||
325 | |||
326 | if (gpioh->inhibit) | ||
327 | continue; | ||
328 | gpioh->inhibit = true; | ||
329 | |||
330 | schedule_work(&gpioh->work); | ||
331 | } | ||
332 | spin_unlock(&priv->lock); | ||
333 | } | 139 | } |