Rev 3192 | Rev 5078 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1117 | serge | 1 | /* |
2 | * Copyright 2008 Advanced Micro Devices, Inc. |
||
3 | * Copyright 2008 Red Hat Inc. |
||
4 | * Copyright 2009 Jerome Glisse. |
||
5 | * |
||
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
7 | * copy of this software and associated documentation files (the "Software"), |
||
8 | * to deal in the Software without restriction, including without limitation |
||
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||
10 | * and/or sell copies of the Software, and to permit persons to whom the |
||
11 | * Software is furnished to do so, subject to the following conditions: |
||
12 | * |
||
13 | * The above copyright notice and this permission notice shall be included in |
||
14 | * all copies or substantial portions of the Software. |
||
15 | * |
||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||
19 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
||
20 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
||
21 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
||
22 | * OTHER DEALINGS IN THE SOFTWARE. |
||
23 | * |
||
24 | * Authors: Dave Airlie |
||
25 | * Alex Deucher |
||
26 | * Jerome Glisse |
||
27 | */ |
||
1179 | serge | 28 | #include |
1963 | serge | 29 | #include |
2997 | Serge | 30 | #include |
31 | #include |
||
1117 | serge | 32 | #include "radeon_reg.h" |
33 | #include "radeon.h" |
||
1963 | serge | 34 | #include "radeon_asic.h" |
1179 | serge | 35 | #include "r100d.h" |
1221 | serge | 36 | #include "rs100d.h" |
37 | #include "rv200d.h" |
||
38 | #include "rv250d.h" |
||
1963 | serge | 39 | #include "atom.h" |
1117 | serge | 40 | |
1221 | serge | 41 | #include |
2997 | Serge | 42 | #include |
1221 | serge | 43 | |
1179 | serge | 44 | #include "r100_reg_safe.h" |
45 | #include "rn50_reg_safe.h" |
||
1221 | serge | 46 | |
47 | /* Firmware Names */ |
||
48 | #define FIRMWARE_R100 "radeon/R100_cp.bin" |
||
49 | #define FIRMWARE_R200 "radeon/R200_cp.bin" |
||
50 | #define FIRMWARE_R300 "radeon/R300_cp.bin" |
||
51 | #define FIRMWARE_R420 "radeon/R420_cp.bin" |
||
52 | #define FIRMWARE_RS690 "radeon/RS690_cp.bin" |
||
53 | #define FIRMWARE_RS600 "radeon/RS600_cp.bin" |
||
54 | #define FIRMWARE_R520 "radeon/R520_cp.bin" |
||
55 | |||
56 | MODULE_FIRMWARE(FIRMWARE_R100); |
||
57 | MODULE_FIRMWARE(FIRMWARE_R200); |
||
58 | MODULE_FIRMWARE(FIRMWARE_R300); |
||
59 | MODULE_FIRMWARE(FIRMWARE_R420); |
||
60 | MODULE_FIRMWARE(FIRMWARE_RS690); |
||
61 | MODULE_FIRMWARE(FIRMWARE_RS600); |
||
62 | MODULE_FIRMWARE(FIRMWARE_R520); |
||
63 | |||
64 | |||
1117 | serge | 65 | /* This files gather functions specifics to: |
66 | * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 |
||
2997 | Serge | 67 | * and others in some cases. |
1117 | serge | 68 | */ |
69 | |||
3764 | Serge | 70 | static bool r100_is_in_vblank(struct radeon_device *rdev, int crtc) |
71 | { |
||
72 | if (crtc == 0) { |
||
73 | if (RREG32(RADEON_CRTC_STATUS) & RADEON_CRTC_VBLANK_CUR) |
||
74 | return true; |
||
75 | else |
||
76 | return false; |
||
77 | } else { |
||
78 | if (RREG32(RADEON_CRTC2_STATUS) & RADEON_CRTC2_VBLANK_CUR) |
||
79 | return true; |
||
80 | else |
||
81 | return false; |
||
82 | } |
||
83 | } |
||
84 | |||
85 | static bool r100_is_counter_moving(struct radeon_device *rdev, int crtc) |
||
86 | { |
||
87 | u32 vline1, vline2; |
||
88 | |||
89 | if (crtc == 0) { |
||
90 | vline1 = (RREG32(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL; |
||
91 | vline2 = (RREG32(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL; |
||
92 | } else { |
||
93 | vline1 = (RREG32(RADEON_CRTC2_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL; |
||
94 | vline2 = (RREG32(RADEON_CRTC2_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL; |
||
95 | } |
||
96 | if (vline1 != vline2) |
||
97 | return true; |
||
98 | else |
||
99 | return false; |
||
100 | } |
||
101 | |||
2997 | Serge | 102 | /** |
103 | * r100_wait_for_vblank - vblank wait asic callback. |
||
104 | * |
||
105 | * @rdev: radeon_device pointer |
||
106 | * @crtc: crtc to wait for vblank on |
||
107 | * |
||
108 | * Wait for vblank on the requested crtc (r1xx-r4xx). |
||
109 | */ |
||
110 | void r100_wait_for_vblank(struct radeon_device *rdev, int crtc) |
||
111 | { |
||
3764 | Serge | 112 | unsigned i = 0; |
2997 | Serge | 113 | |
114 | if (crtc >= rdev->num_crtc) |
||
115 | return; |
||
116 | |||
117 | if (crtc == 0) { |
||
3764 | Serge | 118 | if (!(RREG32(RADEON_CRTC_GEN_CNTL) & RADEON_CRTC_EN)) |
119 | return; |
||
120 | } else { |
||
121 | if (!(RREG32(RADEON_CRTC2_GEN_CNTL) & RADEON_CRTC2_EN)) |
||
122 | return; |
||
123 | } |
||
124 | |||
125 | /* depending on when we hit vblank, we may be close to active; if so, |
||
126 | * wait for another frame. |
||
127 | */ |
||
128 | while (r100_is_in_vblank(rdev, crtc)) { |
||
129 | if (i++ % 100 == 0) { |
||
130 | if (!r100_is_counter_moving(rdev, crtc)) |
||
2997 | Serge | 131 | break; |
132 | } |
||
133 | } |
||
3764 | Serge | 134 | |
135 | while (!r100_is_in_vblank(rdev, crtc)) { |
||
136 | if (i++ % 100 == 0) { |
||
137 | if (!r100_is_counter_moving(rdev, crtc)) |
||
2997 | Serge | 138 | break; |
139 | } |
||
140 | } |
||
141 | } |
||
1963 | serge | 142 | u32 r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) |
143 | { |
||
144 | struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; |
||
145 | u32 tmp = ((u32)crtc_base) | RADEON_CRTC_OFFSET__OFFSET_LOCK; |
||
2997 | Serge | 146 | int i; |
1963 | serge | 147 | |
148 | /* Lock the graphics update lock */ |
||
149 | /* update the scanout addresses */ |
||
150 | WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, tmp); |
||
151 | |||
152 | /* Wait for update_pending to go high. */ |
||
2997 | Serge | 153 | for (i = 0; i < rdev->usec_timeout; i++) { |
154 | if (RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET) |
||
155 | break; |
||
156 | udelay(1); |
||
157 | } |
||
1963 | serge | 158 | DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); |
159 | |||
160 | /* Unlock the lock, so double-buffering can take place inside vblank */ |
||
161 | tmp &= ~RADEON_CRTC_OFFSET__OFFSET_LOCK; |
||
162 | WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, tmp); |
||
163 | |||
164 | /* Return current update_pending status: */ |
||
165 | return RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET; |
||
166 | } |
||
167 | bool r100_gui_idle(struct radeon_device *rdev) |
||
168 | { |
||
169 | if (RREG32(RADEON_RBBM_STATUS) & RADEON_RBBM_ACTIVE) |
||
170 | return false; |
||
171 | else |
||
172 | return true; |
||
173 | } |
||
174 | |||
1321 | serge | 175 | /* hpd for digital panel detect/disconnect */ |
2997 | Serge | 176 | /** |
177 | * r100_hpd_sense - hpd sense callback. |
||
178 | * |
||
179 | * @rdev: radeon_device pointer |
||
180 | * @hpd: hpd (hotplug detect) pin |
||
181 | * |
||
182 | * Checks if a digital monitor is connected (r1xx-r4xx). |
||
183 | * Returns true if connected, false if not connected. |
||
184 | */ |
||
1321 | serge | 185 | bool r100_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd) |
186 | { |
||
187 | bool connected = false; |
||
188 | |||
189 | switch (hpd) { |
||
190 | case RADEON_HPD_1: |
||
191 | if (RREG32(RADEON_FP_GEN_CNTL) & RADEON_FP_DETECT_SENSE) |
||
192 | connected = true; |
||
193 | break; |
||
194 | case RADEON_HPD_2: |
||
195 | if (RREG32(RADEON_FP2_GEN_CNTL) & RADEON_FP2_DETECT_SENSE) |
||
196 | connected = true; |
||
197 | break; |
||
198 | default: |
||
199 | break; |
||
200 | } |
||
201 | return connected; |
||
202 | } |
||
203 | |||
2997 | Serge | 204 | /** |
205 | * r100_hpd_set_polarity - hpd set polarity callback. |
||
206 | * |
||
207 | * @rdev: radeon_device pointer |
||
208 | * @hpd: hpd (hotplug detect) pin |
||
209 | * |
||
210 | * Set the polarity of the hpd pin (r1xx-r4xx). |
||
211 | */ |
||
1321 | serge | 212 | void r100_hpd_set_polarity(struct radeon_device *rdev, |
213 | enum radeon_hpd_id hpd) |
||
214 | { |
||
215 | u32 tmp; |
||
216 | bool connected = r100_hpd_sense(rdev, hpd); |
||
217 | |||
218 | switch (hpd) { |
||
219 | case RADEON_HPD_1: |
||
220 | tmp = RREG32(RADEON_FP_GEN_CNTL); |
||
221 | if (connected) |
||
222 | tmp &= ~RADEON_FP_DETECT_INT_POL; |
||
223 | else |
||
224 | tmp |= RADEON_FP_DETECT_INT_POL; |
||
225 | WREG32(RADEON_FP_GEN_CNTL, tmp); |
||
226 | break; |
||
227 | case RADEON_HPD_2: |
||
228 | tmp = RREG32(RADEON_FP2_GEN_CNTL); |
||
229 | if (connected) |
||
230 | tmp &= ~RADEON_FP2_DETECT_INT_POL; |
||
231 | else |
||
232 | tmp |= RADEON_FP2_DETECT_INT_POL; |
||
233 | WREG32(RADEON_FP2_GEN_CNTL, tmp); |
||
234 | break; |
||
235 | default: |
||
236 | break; |
||
237 | } |
||
238 | } |
||
239 | |||
2997 | Serge | 240 | /** |
241 | * r100_hpd_init - hpd setup callback. |
||
242 | * |