NV50: basic fbcon + misc fixes
[platform/upstream/libdrm.git] / linux-core / nv50_cursor.c
1 /*
2  * Copyright (C) 2008 Maarten Maathuis.
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial
15  * portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  */
26
27 #include "nv50_cursor.h"
28 #include "nv50_crtc.h"
29 #include "nv50_display.h"
30
31 static int nv50_cursor_enable(struct nv50_crtc *crtc)
32 {
33         struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
34
35         NV50_DEBUG("\n");
36
37         NV_WRITE(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(crtc->index), 0x2000);
38         while(NV_READ(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(crtc->index)) & NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_MASK);
39
40         NV_WRITE(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(crtc->index), NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_ON);
41         while((NV_READ(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(crtc->index)) & NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_MASK)
42                 != NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE);
43
44         crtc->cursor->enabled = true;
45
46         return 0;
47 }
48
49 static int nv50_cursor_disable(struct nv50_crtc *crtc)
50 {
51         struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
52
53         NV50_DEBUG("\n");
54
55         NV_WRITE(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(crtc->index), 0);
56         while(NV_READ(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(crtc->index)) & NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_MASK);
57
58         crtc->cursor->enabled = false;
59
60         return 0;
61 }
62
63 /* Calling update or changing the stored cursor state is left to the higher level ioctl's. */
64 static int nv50_cursor_show(struct nv50_crtc *crtc)
65 {
66         struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
67         uint32_t offset = crtc->index * 0x400;
68
69         NV50_DEBUG("\n");
70
71         /* Better not show the cursor when we have none. */
72         /* TODO: is cursor offset actually set? */
73         if (!crtc->cursor->block) {
74                 DRM_ERROR("No cursor available on crtc %d\n", crtc->index);
75                 return -EINVAL;
76         }
77
78         OUT_MODE(NV50_CRTC0_CURSOR_CTRL + offset, NV50_CRTC0_CURSOR_CTRL_SHOW);
79
80         return 0;
81 }
82
83 static int nv50_cursor_hide(struct nv50_crtc *crtc)
84 {
85         struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
86         uint32_t offset = crtc->index * 0x400;
87
88         NV50_DEBUG("\n");
89
90         OUT_MODE(NV50_CRTC0_CURSOR_CTRL + offset, NV50_CRTC0_CURSOR_CTRL_HIDE);
91
92         return 0;
93 }
94
95 static int nv50_cursor_set_pos(struct nv50_crtc *crtc, int x, int y)
96 {
97         struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
98
99         NV_WRITE(NV50_HW_CURSOR_POS(crtc->index), ((y & 0xFFFF) << 16) | (x & 0xFFFF));
100         /* Needed to make the cursor move. */
101         NV_WRITE(NV50_HW_CURSOR_POS_CTRL(crtc->index), 0);
102
103         return 0;
104 }
105
106 static int nv50_cursor_set_offset(struct nv50_crtc *crtc)
107 {
108         struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
109
110         NV50_DEBUG("\n");
111
112         if (crtc->cursor->block) {
113                 OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + crtc->index * 0x400, crtc->cursor->block->start >> 8);
114         } else {
115                 OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + crtc->index * 0x400, 0);
116         }
117
118         return 0;
119 }
120
121 static int nv50_cursor_set_bo(struct nv50_crtc *crtc, drm_handle_t handle)
122 {
123         struct mem_block *block = NULL;
124         struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
125
126         NV50_DEBUG("\n");
127
128         block = find_block_by_handle(dev_priv->fb_heap, handle);
129
130         if (block) {
131                 bool first_time = false;
132                 if (!crtc->cursor->block)
133                         first_time = true;
134
135                 crtc->cursor->block = block;
136
137                 /* set the cursor offset cursor */
138                 if (first_time) {
139                         crtc->cursor->set_offset(crtc);
140                         if (crtc->cursor->visible)
141                                 crtc->cursor->show(crtc);
142                 }
143         } else {
144                 DRM_ERROR("Unable to find cursor bo with handle 0x%X\n", handle);
145                 return -EINVAL;
146         }
147
148         return 0;
149 }
150
151 int nv50_cursor_create(struct nv50_crtc *crtc)
152 {
153         NV50_DEBUG("\n");
154
155         if (!crtc)
156                 return -EINVAL;
157
158         crtc->cursor = kzalloc(sizeof(struct nv50_cursor), GFP_KERNEL);
159         if (!crtc->cursor)
160                 return -ENOMEM;
161
162         /* function pointers */
163         crtc->cursor->show = nv50_cursor_show;
164         crtc->cursor->hide = nv50_cursor_hide;
165         crtc->cursor->set_pos = nv50_cursor_set_pos;
166         crtc->cursor->set_offset = nv50_cursor_set_offset;
167         crtc->cursor->set_bo = nv50_cursor_set_bo;
168         crtc->cursor->enable = nv50_cursor_enable;
169         crtc->cursor->disable = nv50_cursor_disable;
170
171         return 0;
172 }
173
174 int nv50_cursor_destroy(struct nv50_crtc *crtc)
175 {
176         int rval = 0;
177
178         NV50_DEBUG("\n");
179
180         if (!crtc)
181                 return -EINVAL;
182
183         if (crtc->cursor->enabled) {
184                 rval = crtc->cursor->disable(crtc);
185                 if (rval != 0)
186                         return rval;
187         }
188
189         kfree(crtc->cursor);
190         crtc->cursor = NULL;
191
192         return 0;
193 }