1926deccbSFrançois Tigeot /*
2926deccbSFrançois Tigeot * Copyright 2008 Advanced Micro Devices, Inc.
3926deccbSFrançois Tigeot * Copyright 2008 Red Hat Inc.
4926deccbSFrançois Tigeot * Copyright 2009 Jerome Glisse.
5926deccbSFrançois Tigeot *
6926deccbSFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a
7926deccbSFrançois Tigeot * copy of this software and associated documentation files (the "Software"),
8926deccbSFrançois Tigeot * to deal in the Software without restriction, including without limitation
9926deccbSFrançois Tigeot * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10926deccbSFrançois Tigeot * and/or sell copies of the Software, and to permit persons to whom the
11926deccbSFrançois Tigeot * Software is furnished to do so, subject to the following conditions:
12926deccbSFrançois Tigeot *
13926deccbSFrançois Tigeot * The above copyright notice and this permission notice shall be included in
14926deccbSFrançois Tigeot * all copies or substantial portions of the Software.
15926deccbSFrançois Tigeot *
16926deccbSFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17926deccbSFrançois Tigeot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18926deccbSFrançois Tigeot * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19926deccbSFrançois Tigeot * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20926deccbSFrançois Tigeot * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21926deccbSFrançois Tigeot * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22926deccbSFrançois Tigeot * OTHER DEALINGS IN THE SOFTWARE.
23926deccbSFrançois Tigeot *
24926deccbSFrançois Tigeot * Authors: Dave Airlie
25926deccbSFrançois Tigeot * Alex Deucher
26926deccbSFrançois Tigeot * Jerome Glisse
27926deccbSFrançois Tigeot */
28926deccbSFrançois Tigeot /* RS600 / Radeon X1250/X1270 integrated GPU
29926deccbSFrançois Tigeot *
30926deccbSFrançois Tigeot * This file gather function specific to RS600 which is the IGP of
31926deccbSFrançois Tigeot * the X1250/X1270 family supporting intel CPU (while RS690/RS740
32926deccbSFrançois Tigeot * is the X1250/X1270 supporting AMD CPU). The display engine are
33926deccbSFrançois Tigeot * the avivo one, bios is an atombios, 3D block are the one of the
34926deccbSFrançois Tigeot * R4XX family. The GART is different from the RS400 one and is very
35926deccbSFrançois Tigeot * close to the one of the R600 family (R600 likely being an evolution
36926deccbSFrançois Tigeot * of the RS600 GART block).
37926deccbSFrançois Tigeot */
38926deccbSFrançois Tigeot #include <drm/drmP.h>
39926deccbSFrançois Tigeot #include "radeon.h"
40926deccbSFrançois Tigeot #include "radeon_asic.h"
41c59a5c48SFrançois Tigeot #include "radeon_audio.h"
42926deccbSFrançois Tigeot #include "atom.h"
43926deccbSFrançois Tigeot #include "rs600d.h"
44926deccbSFrançois Tigeot
45926deccbSFrançois Tigeot #include "rs600_reg_safe.h"
46926deccbSFrançois Tigeot
47926deccbSFrançois Tigeot static void rs600_gpu_init(struct radeon_device *rdev);
48926deccbSFrançois Tigeot
49926deccbSFrançois Tigeot static const u32 crtc_offsets[2] =
50926deccbSFrançois Tigeot {
51926deccbSFrançois Tigeot 0,
52926deccbSFrançois Tigeot AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL
53926deccbSFrançois Tigeot };
54926deccbSFrançois Tigeot
avivo_is_in_vblank(struct radeon_device * rdev,int crtc)55f43cf1b1SMichael Neumann static bool avivo_is_in_vblank(struct radeon_device *rdev, int crtc)
56f43cf1b1SMichael Neumann {
57f43cf1b1SMichael Neumann if (RREG32(AVIVO_D1CRTC_STATUS + crtc_offsets[crtc]) & AVIVO_D1CRTC_V_BLANK)
58f43cf1b1SMichael Neumann return true;
59f43cf1b1SMichael Neumann else
60f43cf1b1SMichael Neumann return false;
61f43cf1b1SMichael Neumann }
62f43cf1b1SMichael Neumann
avivo_is_counter_moving(struct radeon_device * rdev,int crtc)63f43cf1b1SMichael Neumann static bool avivo_is_counter_moving(struct radeon_device *rdev, int crtc)
64f43cf1b1SMichael Neumann {
65f43cf1b1SMichael Neumann u32 pos1, pos2;
66f43cf1b1SMichael Neumann
67f43cf1b1SMichael Neumann pos1 = RREG32(AVIVO_D1CRTC_STATUS_POSITION + crtc_offsets[crtc]);
68f43cf1b1SMichael Neumann pos2 = RREG32(AVIVO_D1CRTC_STATUS_POSITION + crtc_offsets[crtc]);
69f43cf1b1SMichael Neumann
70f43cf1b1SMichael Neumann if (pos1 != pos2)
71f43cf1b1SMichael Neumann return true;
72f43cf1b1SMichael Neumann else
73f43cf1b1SMichael Neumann return false;
74f43cf1b1SMichael Neumann }
75f43cf1b1SMichael Neumann
76f43cf1b1SMichael Neumann /**
77f43cf1b1SMichael Neumann * avivo_wait_for_vblank - vblank wait asic callback.
78f43cf1b1SMichael Neumann *
79f43cf1b1SMichael Neumann * @rdev: radeon_device pointer
80f43cf1b1SMichael Neumann * @crtc: crtc to wait for vblank on
81f43cf1b1SMichael Neumann *
82f43cf1b1SMichael Neumann * Wait for vblank on the requested crtc (r5xx-r7xx).
83f43cf1b1SMichael Neumann */
avivo_wait_for_vblank(struct radeon_device * rdev,int crtc)84926deccbSFrançois Tigeot void avivo_wait_for_vblank(struct radeon_device *rdev, int crtc)
85926deccbSFrançois Tigeot {
86f43cf1b1SMichael Neumann unsigned i = 0;
87926deccbSFrançois Tigeot
88926deccbSFrançois Tigeot if (crtc >= rdev->num_crtc)
89926deccbSFrançois Tigeot return;
90926deccbSFrançois Tigeot
91f43cf1b1SMichael Neumann if (!(RREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[crtc]) & AVIVO_CRTC_EN))
92f43cf1b1SMichael Neumann return;
93f43cf1b1SMichael Neumann
94f43cf1b1SMichael Neumann /* depending on when we hit vblank, we may be close to active; if so,
95f43cf1b1SMichael Neumann * wait for another frame.
96f43cf1b1SMichael Neumann */
97f43cf1b1SMichael Neumann while (avivo_is_in_vblank(rdev, crtc)) {
98f43cf1b1SMichael Neumann if (i++ % 100 == 0) {
99f43cf1b1SMichael Neumann if (!avivo_is_counter_moving(rdev, crtc))
100926deccbSFrançois Tigeot break;
101926deccbSFrançois Tigeot }
102f43cf1b1SMichael Neumann }
103f43cf1b1SMichael Neumann
104f43cf1b1SMichael Neumann while (!avivo_is_in_vblank(rdev, crtc)) {
105f43cf1b1SMichael Neumann if (i++ % 100 == 0) {
106f43cf1b1SMichael Neumann if (!avivo_is_counter_moving(rdev, crtc))
107926deccbSFrançois Tigeot break;
108926deccbSFrançois Tigeot }
109926deccbSFrançois Tigeot }
110926deccbSFrançois Tigeot }
111926deccbSFrançois Tigeot
rs600_page_flip(struct radeon_device * rdev,int crtc_id,u64 crtc_base,bool async)112d78d3a22SFrançois Tigeot void rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base, bool async)
113926deccbSFrançois Tigeot {
114926deccbSFrançois Tigeot struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
115926deccbSFrançois Tigeot u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset);
116926deccbSFrançois Tigeot int i;
117926deccbSFrançois Tigeot
118926deccbSFrançois Tigeot /* Lock the graphics update lock */
119926deccbSFrançois Tigeot tmp |= AVIVO_D1GRPH_UPDATE_LOCK;
120926deccbSFrançois Tigeot WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp);
121926deccbSFrançois Tigeot
122926deccbSFrançois Tigeot /* update the scanout addresses */
123d78d3a22SFrançois Tigeot WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset,
124d78d3a22SFrançois Tigeot async ? AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN : 0);
125926deccbSFrançois Tigeot WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
126926deccbSFrançois Tigeot (u32)crtc_base);
127926deccbSFrançois Tigeot WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
128926deccbSFrançois Tigeot (u32)crtc_base);
129926deccbSFrançois Tigeot
130926deccbSFrançois Tigeot /* Wait for update_pending to go high. */
131926deccbSFrançois Tigeot for (i = 0; i < rdev->usec_timeout; i++) {
132926deccbSFrançois Tigeot if (RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING)
133926deccbSFrançois Tigeot break;
134c4ef309bSzrj udelay(1);
135926deccbSFrançois Tigeot }
136926deccbSFrançois Tigeot DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n");
137926deccbSFrançois Tigeot
138926deccbSFrançois Tigeot /* Unlock the lock, so double-buffering can take place inside vblank */
139926deccbSFrançois Tigeot tmp &= ~AVIVO_D1GRPH_UPDATE_LOCK;
140926deccbSFrançois Tigeot WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp);
141c6f73aabSFrançois Tigeot }
142c6f73aabSFrançois Tigeot
rs600_page_flip_pending(struct radeon_device * rdev,int crtc_id)143c6f73aabSFrançois Tigeot bool rs600_page_flip_pending(struct radeon_device *rdev, int crtc_id)
144c6f73aabSFrançois Tigeot {
145c6f73aabSFrançois Tigeot struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
146926deccbSFrançois Tigeot
147926deccbSFrançois Tigeot /* Return current update_pending status: */
148c6f73aabSFrançois Tigeot return !!(RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) &
149c6f73aabSFrançois Tigeot AVIVO_D1GRPH_SURFACE_UPDATE_PENDING);
150c6f73aabSFrançois Tigeot }
151c6f73aabSFrançois Tigeot
avivo_program_fmt(struct drm_encoder * encoder)152c6f73aabSFrançois Tigeot void avivo_program_fmt(struct drm_encoder *encoder)
153c6f73aabSFrançois Tigeot {
154c6f73aabSFrançois Tigeot struct drm_device *dev = encoder->dev;
155c6f73aabSFrançois Tigeot struct radeon_device *rdev = dev->dev_private;
156c6f73aabSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
157c6f73aabSFrançois Tigeot struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
158c6f73aabSFrançois Tigeot int bpc = 0;
159c6f73aabSFrançois Tigeot u32 tmp = 0;
160c6f73aabSFrançois Tigeot enum radeon_connector_dither dither = RADEON_FMT_DITHER_DISABLE;
161c6f73aabSFrançois Tigeot
162c6f73aabSFrançois Tigeot if (connector) {
163c6f73aabSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector);
164c6f73aabSFrançois Tigeot bpc = radeon_get_monitor_bpc(connector);
165c6f73aabSFrançois Tigeot dither = radeon_connector->dither;
166c6f73aabSFrançois Tigeot }
167c6f73aabSFrançois Tigeot
168c6f73aabSFrançois Tigeot /* LVDS FMT is set up by atom */
169c6f73aabSFrançois Tigeot if (radeon_encoder->devices & ATOM_DEVICE_LCD_SUPPORT)
170c6f73aabSFrançois Tigeot return;
171c6f73aabSFrançois Tigeot
172c6f73aabSFrançois Tigeot if (bpc == 0)
173c6f73aabSFrançois Tigeot return;
174c6f73aabSFrançois Tigeot
175c6f73aabSFrançois Tigeot switch (bpc) {
176c6f73aabSFrançois Tigeot case 6:
177c6f73aabSFrançois Tigeot if (dither == RADEON_FMT_DITHER_ENABLE)
178c6f73aabSFrançois Tigeot /* XXX sort out optimal dither settings */
179c6f73aabSFrançois Tigeot tmp |= AVIVO_TMDS_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN;
180c6f73aabSFrançois Tigeot else
181c6f73aabSFrançois Tigeot tmp |= AVIVO_TMDS_BIT_DEPTH_CONTROL_TRUNCATE_EN;
182c6f73aabSFrançois Tigeot break;
183c6f73aabSFrançois Tigeot case 8:
184c6f73aabSFrançois Tigeot if (dither == RADEON_FMT_DITHER_ENABLE)
185c6f73aabSFrançois Tigeot /* XXX sort out optimal dither settings */
186c6f73aabSFrançois Tigeot tmp |= (AVIVO_TMDS_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN |
187c6f73aabSFrançois Tigeot AVIVO_TMDS_BIT_DEPTH_CONTROL_SPATIAL_DITHER_DEPTH);
188c6f73aabSFrançois Tigeot else
189c6f73aabSFrançois Tigeot tmp |= (AVIVO_TMDS_BIT_DEPTH_CONTROL_TRUNCATE_EN |
190c6f73aabSFrançois Tigeot AVIVO_TMDS_BIT_DEPTH_CONTROL_TRUNCATE_DEPTH);
191c6f73aabSFrançois Tigeot break;
192c6f73aabSFrançois Tigeot case 10:
193c6f73aabSFrançois Tigeot default:
194c6f73aabSFrançois Tigeot /* not needed */
195c6f73aabSFrançois Tigeot break;
196c6f73aabSFrançois Tigeot }
197c6f73aabSFrançois Tigeot
198c6f73aabSFrançois Tigeot switch (radeon_encoder->encoder_id) {
199c6f73aabSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
200c6f73aabSFrançois Tigeot WREG32(AVIVO_TMDSA_BIT_DEPTH_CONTROL, tmp);
201c6f73aabSFrançois Tigeot break;
202c6f73aabSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
203c6f73aabSFrançois Tigeot WREG32(AVIVO_LVTMA_BIT_DEPTH_CONTROL, tmp);
204c6f73aabSFrançois Tigeot break;
205c6f73aabSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
206c6f73aabSFrançois Tigeot WREG32(AVIVO_DVOA_BIT_DEPTH_CONTROL, tmp);
207c6f73aabSFrançois Tigeot break;
208c6f73aabSFrançois Tigeot case ENCODER_OBJECT_ID_INTERNAL_DDI:
209c6f73aabSFrançois Tigeot WREG32(AVIVO_DDIA_BIT_DEPTH_CONTROL, tmp);
210c6f73aabSFrançois Tigeot break;
211c6f73aabSFrançois Tigeot default:
212c6f73aabSFrançois Tigeot break;
213c6f73aabSFrançois Tigeot }
214926deccbSFrançois Tigeot }
215926deccbSFrançois Tigeot
rs600_pm_misc(struct radeon_device * rdev)216926deccbSFrançois Tigeot void rs600_pm_misc(struct radeon_device *rdev)
217926deccbSFrançois Tigeot {
218926deccbSFrançois Tigeot int requested_index = rdev->pm.requested_power_state_index;
219926deccbSFrançois Tigeot struct radeon_power_state *ps = &rdev->pm.power_state[requested_index];
220926deccbSFrançois Tigeot struct radeon_voltage *voltage = &ps->clock_info[0].voltage;
221926deccbSFrançois Tigeot u32 tmp, dyn_pwrmgt_sclk_length, dyn_sclk_vol_cntl;
222926deccbSFrançois Tigeot u32 hdp_dyn_cntl, /*mc_host_dyn_cntl,*/ dyn_backbias_cntl;
223926deccbSFrançois Tigeot
224926deccbSFrançois Tigeot if ((voltage->type == VOLTAGE_GPIO) && (voltage->gpio.valid)) {
225926deccbSFrançois Tigeot if (ps->misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) {
226926deccbSFrançois Tigeot tmp = RREG32(voltage->gpio.reg);
227926deccbSFrançois Tigeot if (voltage->active_high)
228926deccbSFrançois Tigeot tmp |= voltage->gpio.mask;
229926deccbSFrançois Tigeot else
230926deccbSFrançois Tigeot tmp &= ~(voltage->gpio.mask);
231926deccbSFrançois Tigeot WREG32(voltage->gpio.reg, tmp);
232926deccbSFrançois Tigeot if (voltage->delay)
233c4ef309bSzrj udelay(voltage->delay);
234926deccbSFrançois Tigeot } else {
235926deccbSFrançois Tigeot tmp = RREG32(voltage->gpio.reg);
236926deccbSFrançois Tigeot if (voltage->active_high)
237926deccbSFrançois Tigeot tmp &= ~voltage->gpio.mask;
238926deccbSFrançois Tigeot else
239926deccbSFrançois Tigeot tmp |= voltage->gpio.mask;
240926deccbSFrançois Tigeot WREG32(voltage->gpio.reg, tmp);
241926deccbSFrançois Tigeot if (voltage->delay)
242c4ef309bSzrj udelay(voltage->delay);
243926deccbSFrançois Tigeot }
244926deccbSFrançois Tigeot } else if (voltage->type == VOLTAGE_VDDC)
245926deccbSFrançois Tigeot radeon_atom_set_voltage(rdev, voltage->vddc_id, SET_VOLTAGE_TYPE_ASIC_VDDC);
246926deccbSFrançois Tigeot
247926deccbSFrançois Tigeot dyn_pwrmgt_sclk_length = RREG32_PLL(DYN_PWRMGT_SCLK_LENGTH);
248926deccbSFrançois Tigeot dyn_pwrmgt_sclk_length &= ~REDUCED_POWER_SCLK_HILEN(0xf);
249926deccbSFrançois Tigeot dyn_pwrmgt_sclk_length &= ~REDUCED_POWER_SCLK_LOLEN(0xf);
250926deccbSFrançois Tigeot if (ps->misc & ATOM_PM_MISCINFO_ASIC_REDUCED_SPEED_SCLK_EN) {
251926deccbSFrançois Tigeot if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_2) {
252926deccbSFrançois Tigeot dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_HILEN(2);
253926deccbSFrançois Tigeot dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_LOLEN(2);
254926deccbSFrançois Tigeot } else if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_4) {
255926deccbSFrançois Tigeot dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_HILEN(4);
256926deccbSFrançois Tigeot dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_LOLEN(4);
257926deccbSFrançois Tigeot }
258926deccbSFrançois Tigeot } else {
259926deccbSFrançois Tigeot dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_HILEN(1);
260926deccbSFrançois Tigeot dyn_pwrmgt_sclk_length |= REDUCED_POWER_SCLK_LOLEN(1);
261926deccbSFrançois Tigeot }
262926deccbSFrançois Tigeot WREG32_PLL(DYN_PWRMGT_SCLK_LENGTH, dyn_pwrmgt_sclk_length);
263926deccbSFrançois Tigeot
264926deccbSFrançois Tigeot dyn_sclk_vol_cntl = RREG32_PLL(DYN_SCLK_VOL_CNTL);
265926deccbSFrançois Tigeot if (ps->misc & ATOM_PM_MISCINFO_ASIC_DYNAMIC_VOLTAGE_EN) {
266926deccbSFrançois Tigeot dyn_sclk_vol_cntl |= IO_CG_VOLTAGE_DROP;
267926deccbSFrançois Tigeot if (voltage->delay) {
268926deccbSFrançois Tigeot dyn_sclk_vol_cntl |= VOLTAGE_DROP_SYNC;
269926deccbSFrançois Tigeot dyn_sclk_vol_cntl |= VOLTAGE_DELAY_SEL(voltage->delay);
270926deccbSFrançois Tigeot } else
271926deccbSFrançois Tigeot dyn_sclk_vol_cntl &= ~VOLTAGE_DROP_SYNC;
272926deccbSFrançois Tigeot } else
273926deccbSFrançois Tigeot dyn_sclk_vol_cntl &= ~IO_CG_VOLTAGE_DROP;
274926deccbSFrançois Tigeot WREG32_PLL(DYN_SCLK_VOL_CNTL, dyn_sclk_vol_cntl);
275926deccbSFrançois Tigeot
276926deccbSFrançois Tigeot hdp_dyn_cntl = RREG32_PLL(HDP_DYN_CNTL);
277926deccbSFrançois Tigeot if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_HDP_BLOCK_EN)
278926deccbSFrançois Tigeot hdp_dyn_cntl &= ~HDP_FORCEON;
279926deccbSFrançois Tigeot else
280926deccbSFrançois Tigeot hdp_dyn_cntl |= HDP_FORCEON;
281926deccbSFrançois Tigeot WREG32_PLL(HDP_DYN_CNTL, hdp_dyn_cntl);
282926deccbSFrançois Tigeot #if 0
283926deccbSFrançois Tigeot /* mc_host_dyn seems to cause hangs from time to time */
284926deccbSFrançois Tigeot mc_host_dyn_cntl = RREG32_PLL(MC_HOST_DYN_CNTL);
285926deccbSFrançois Tigeot if (ps->misc & ATOM_PM_MISCINFO_DYNAMIC_MC_HOST_BLOCK_EN)
286926deccbSFrançois Tigeot mc_host_dyn_cntl &= ~MC_HOST_FORCEON;
287926deccbSFrançois Tigeot else
288926deccbSFrançois Tigeot mc_host_dyn_cntl |= MC_HOST_FORCEON;
289926deccbSFrançois Tigeot WREG32_PLL(MC_HOST_DYN_CNTL, mc_host_dyn_cntl);
290926deccbSFrançois Tigeot #endif
291926deccbSFrançois Tigeot dyn_backbias_cntl = RREG32_PLL(DYN_BACKBIAS_CNTL);
292926deccbSFrançois Tigeot if (ps->misc & ATOM_PM_MISCINFO2_DYNAMIC_BACK_BIAS_EN)
293926deccbSFrançois Tigeot dyn_backbias_cntl |= IO_CG_BACKBIAS_EN;
294926deccbSFrançois Tigeot else
295926deccbSFrançois Tigeot dyn_backbias_cntl &= ~IO_CG_BACKBIAS_EN;
296926deccbSFrançois Tigeot WREG32_PLL(DYN_BACKBIAS_CNTL, dyn_backbias_cntl);
297926deccbSFrançois Tigeot
298926deccbSFrançois Tigeot /* set pcie lanes */
299926deccbSFrançois Tigeot if ((rdev->flags & RADEON_IS_PCIE) &&
300926deccbSFrançois Tigeot !(rdev->flags & RADEON_IS_IGP) &&
301926deccbSFrançois Tigeot rdev->asic->pm.set_pcie_lanes &&
302926deccbSFrançois Tigeot (ps->pcie_lanes !=
303926deccbSFrançois Tigeot rdev->pm.power_state[rdev->pm.current_power_state_index].pcie_lanes)) {
304926deccbSFrançois Tigeot radeon_set_pcie_lanes(rdev,
305926deccbSFrançois Tigeot ps->pcie_lanes);
306926deccbSFrançois Tigeot DRM_DEBUG("Setting: p: %d\n", ps->pcie_lanes);
307926deccbSFrançois Tigeot }
308926deccbSFrançois Tigeot }
309926deccbSFrançois Tigeot
rs600_pm_prepare(struct radeon_device * rdev)310926deccbSFrançois Tigeot void rs600_pm_prepare(struct radeon_device *rdev)
311926deccbSFrançois Tigeot {
312926deccbSFrançois Tigeot struct drm_device *ddev = rdev->ddev;
313926deccbSFrançois Tigeot struct drm_crtc *crtc;
314926deccbSFrançois Tigeot struct radeon_crtc *radeon_crtc;
315926deccbSFrançois Tigeot u32 tmp;
316926deccbSFrançois Tigeot
317926deccbSFrançois Tigeot /* disable any active CRTCs */
318926deccbSFrançois Tigeot list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) {
319926deccbSFrançois Tigeot radeon_crtc = to_radeon_crtc(crtc);
320926deccbSFrançois Tigeot if (radeon_crtc->enabled) {
321926deccbSFrançois Tigeot tmp = RREG32(AVIVO_D1CRTC_CONTROL + radeon_crtc->crtc_offset);
322926deccbSFrançois Tigeot tmp |= AVIVO_CRTC_DISP_READ_REQUEST_DISABLE;
323926deccbSFrançois Tigeot WREG32(AVIVO_D1CRTC_CONTROL + radeon_crtc->crtc_offset, tmp);
324926deccbSFrançois Tigeot }
325926deccbSFrançois Tigeot }
326926deccbSFrançois Tigeot }
327926deccbSFrançois Tigeot
rs600_pm_finish(struct radeon_device * rdev)328926deccbSFrançois Tigeot void rs600_pm_finish(struct radeon_device *rdev)
329926deccbSFrançois Tigeot {
330926deccbSFrançois Tigeot struct drm_device *ddev = rdev->ddev;
331926deccbSFrançois Tigeot struct drm_crtc *crtc;
332926deccbSFrançois Tigeot struct radeon_crtc *radeon_crtc;
333926deccbSFrançois Tigeot u32 tmp;
334926deccbSFrançois Tigeot
335926deccbSFrançois Tigeot /* enable any active CRTCs */
336926deccbSFrançois Tigeot list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) {
337926deccbSFrançois Tigeot radeon_crtc = to_radeon_crtc(crtc);
338926deccbSFrançois Tigeot if (radeon_crtc->enabled) {
339926deccbSFrançois Tigeot tmp = RREG32(AVIVO_D1CRTC_CONTROL + radeon_crtc->crtc_offset);
340926deccbSFrançois Tigeot tmp &= ~AVIVO_CRTC_DISP_READ_REQUEST_DISABLE;
341926deccbSFrançois Tigeot WREG32(AVIVO_D1CRTC_CONTROL + radeon_crtc->crtc_offset, tmp);
342926deccbSFrançois Tigeot }
343926deccbSFrançois Tigeot }
344926deccbSFrançois Tigeot }
345926deccbSFrançois Tigeot
346926deccbSFrançois Tigeot /* hpd for digital panel detect/disconnect */
rs600_hpd_sense(struct radeon_device * rdev,enum radeon_hpd_id hpd)347926deccbSFrançois Tigeot bool rs600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd)
348926deccbSFrançois Tigeot {
349926deccbSFrançois Tigeot u32 tmp;
350926deccbSFrançois Tigeot bool connected = false;
351926deccbSFrançois Tigeot
352926deccbSFrançois Tigeot switch (hpd) {
353926deccbSFrançois Tigeot case RADEON_HPD_1:
354926deccbSFrançois Tigeot tmp = RREG32(R_007D04_DC_HOT_PLUG_DETECT1_INT_STATUS);
355926deccbSFrançois Tigeot if (G_007D04_DC_HOT_PLUG_DETECT1_SENSE(tmp))
356926deccbSFrançois Tigeot connected = true;
357926deccbSFrançois Tigeot break;
358926deccbSFrançois Tigeot case RADEON_HPD_2:
359926deccbSFrançois Tigeot tmp = RREG32(R_007D14_DC_HOT_PLUG_DETECT2_INT_STATUS);
360926deccbSFrançois Tigeot if (G_007D14_DC_HOT_PLUG_DETECT2_SENSE(tmp))
361926deccbSFrançois Tigeot connected = true;
362926deccbSFrançois Tigeot break;
363926deccbSFrançois Tigeot default:
364926deccbSFrançois Tigeot break;
365926deccbSFrançois Tigeot }
366926deccbSFrançois Tigeot return connected;
367926deccbSFrançois Tigeot }
368926deccbSFrançois Tigeot
rs600_hpd_set_polarity(struct radeon_device * rdev,enum radeon_hpd_id hpd)369926deccbSFrançois Tigeot void rs600_hpd_set_polarity(struct radeon_device *rdev,
370926deccbSFrançois Tigeot enum radeon_hpd_id hpd)
371926deccbSFrançois Tigeot {
372926deccbSFrançois Tigeot u32 tmp;
373926deccbSFrançois Tigeot bool connected = rs600_hpd_sense(rdev, hpd);
374926deccbSFrançois Tigeot
375926deccbSFrançois Tigeot switch (hpd) {
376926deccbSFrançois Tigeot case RADEON_HPD_1:
377926deccbSFrançois Tigeot tmp = RREG32(R_007D08_DC_HOT_PLUG_DETECT1_INT_CONTROL);
378926deccbSFrançois Tigeot if (connected)
379926deccbSFrançois Tigeot tmp &= ~S_007D08_DC_HOT_PLUG_DETECT1_INT_POLARITY(1);
380926deccbSFrançois Tigeot else
381926deccbSFrançois Tigeot tmp |= S_007D08_DC_HOT_PLUG_DETECT1_INT_POLARITY(1);
382926deccbSFrançois Tigeot WREG32(R_007D08_DC_HOT_PLUG_DETECT1_INT_CONTROL, tmp);
383926deccbSFrançois Tigeot break;
384926deccbSFrançois Tigeot case RADEON_HPD_2:
385926deccbSFrançois Tigeot tmp = RREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL);
386926deccbSFrançois Tigeot if (connected)
387926deccbSFrançois Tigeot tmp &= ~S_007D18_DC_HOT_PLUG_DETECT2_INT_POLARITY(1);
388926deccbSFrançois Tigeot else
389926deccbSFrançois Tigeot tmp |= S_007D18_DC_HOT_PLUG_DETECT2_INT_POLARITY(1);
390926deccbSFrançois Tigeot WREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL, tmp);
391926deccbSFrançois Tigeot break;
392926deccbSFrançois Tigeot default:
393926deccbSFrançois Tigeot break;
394926deccbSFrançois Tigeot }
395926deccbSFrançois Tigeot }
396926deccbSFrançois Tigeot
rs600_hpd_init(struct radeon_device * rdev)397926deccbSFrançois Tigeot void rs600_hpd_init(struct radeon_device *rdev)
398926deccbSFrançois Tigeot {
399926deccbSFrançois Tigeot struct drm_device *dev = rdev->ddev;
400926deccbSFrançois Tigeot struct drm_connector *connector;
401926deccbSFrançois Tigeot unsigned enable = 0;
402926deccbSFrançois Tigeot
403926deccbSFrançois Tigeot list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
404926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector);
405926deccbSFrançois Tigeot switch (radeon_connector->hpd.hpd) {
406926deccbSFrançois Tigeot case RADEON_HPD_1:
407926deccbSFrançois Tigeot WREG32(R_007D00_DC_HOT_PLUG_DETECT1_CONTROL,
408926deccbSFrançois Tigeot S_007D00_DC_HOT_PLUG_DETECT1_EN(1));
409926deccbSFrançois Tigeot break;
410926deccbSFrançois Tigeot case RADEON_HPD_2:
411926deccbSFrançois Tigeot WREG32(R_007D10_DC_HOT_PLUG_DETECT2_CONTROL,
412926deccbSFrançois Tigeot S_007D10_DC_HOT_PLUG_DETECT2_EN(1));
413926deccbSFrançois Tigeot break;
414926deccbSFrançois Tigeot default:
415926deccbSFrançois Tigeot break;
416926deccbSFrançois Tigeot }
417d78d3a22SFrançois Tigeot if (radeon_connector->hpd.hpd != RADEON_HPD_NONE)
418926deccbSFrançois Tigeot enable |= 1 << radeon_connector->hpd.hpd;
419926deccbSFrançois Tigeot radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
420926deccbSFrançois Tigeot }
421926deccbSFrançois Tigeot radeon_irq_kms_enable_hpd(rdev, enable);
422926deccbSFrançois Tigeot }
423926deccbSFrançois Tigeot
rs600_hpd_fini(struct radeon_device * rdev)424926deccbSFrançois Tigeot void rs600_hpd_fini(struct radeon_device *rdev)
425926deccbSFrançois Tigeot {
426926deccbSFrançois Tigeot struct drm_device *dev = rdev->ddev;
427926deccbSFrançois Tigeot struct drm_connector *connector;
428926deccbSFrançois Tigeot unsigned disable = 0;
429926deccbSFrançois Tigeot
430926deccbSFrançois Tigeot list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
431926deccbSFrançois Tigeot struct radeon_connector *radeon_connector = to_radeon_connector(connector);
432926deccbSFrançois Tigeot switch (radeon_connector->hpd.hpd) {
433926deccbSFrançois Tigeot case RADEON_HPD_1:
434926deccbSFrançois Tigeot WREG32(R_007D00_DC_HOT_PLUG_DETECT1_CONTROL,
435926deccbSFrançois Tigeot S_007D00_DC_HOT_PLUG_DETECT1_EN(0));
436926deccbSFrançois Tigeot break;
437926deccbSFrançois Tigeot case RADEON_HPD_2:
438926deccbSFrançois Tigeot WREG32(R_007D10_DC_HOT_PLUG_DETECT2_CONTROL,
439926deccbSFrançois Tigeot S_007D10_DC_HOT_PLUG_DETECT2_EN(0));
440926deccbSFrançois Tigeot break;
441926deccbSFrançois Tigeot default:
442926deccbSFrançois Tigeot break;
443926deccbSFrançois Tigeot }
444d78d3a22SFrançois Tigeot if (radeon_connector->hpd.hpd != RADEON_HPD_NONE)
445926deccbSFrançois Tigeot disable |= 1 << radeon_connector->hpd.hpd;
446926deccbSFrançois Tigeot }
447926deccbSFrançois Tigeot radeon_irq_kms_disable_hpd(rdev, disable);
448926deccbSFrançois Tigeot }
449926deccbSFrançois Tigeot
rs600_asic_reset(struct radeon_device * rdev,bool hard)450d78d3a22SFrançois Tigeot int rs600_asic_reset(struct radeon_device *rdev, bool hard)
451926deccbSFrançois Tigeot {
452926deccbSFrançois Tigeot struct rv515_mc_save save;
453926deccbSFrançois Tigeot u32 status, tmp;
454926deccbSFrançois Tigeot int ret = 0;
455926deccbSFrançois Tigeot
456926deccbSFrançois Tigeot status = RREG32(R_000E40_RBBM_STATUS);
457926deccbSFrançois Tigeot if (!G_000E40_GUI_ACTIVE(status)) {
458926deccbSFrançois Tigeot return 0;
459926deccbSFrançois Tigeot }
460926deccbSFrançois Tigeot /* Stops all mc clients */
461926deccbSFrançois Tigeot rv515_mc_stop(rdev, &save);
462926deccbSFrançois Tigeot status = RREG32(R_000E40_RBBM_STATUS);
463926deccbSFrançois Tigeot dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
464926deccbSFrançois Tigeot /* stop CP */
465926deccbSFrançois Tigeot WREG32(RADEON_CP_CSQ_CNTL, 0);
466926deccbSFrançois Tigeot tmp = RREG32(RADEON_CP_RB_CNTL);
467926deccbSFrançois Tigeot WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA);
468926deccbSFrançois Tigeot WREG32(RADEON_CP_RB_RPTR_WR, 0);
469926deccbSFrançois Tigeot WREG32(RADEON_CP_RB_WPTR, 0);
470926deccbSFrançois Tigeot WREG32(RADEON_CP_RB_CNTL, tmp);
471fb572d17SFrançois Tigeot pci_save_state(device_get_parent(rdev->dev->bsddev));
472926deccbSFrançois Tigeot /* disable bus mastering */
473fb572d17SFrançois Tigeot pci_disable_busmaster(rdev->dev->bsddev);
474c4ef309bSzrj mdelay(1);
475926deccbSFrançois Tigeot /* reset GA+VAP */
476926deccbSFrançois Tigeot WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_VAP(1) |
477926deccbSFrançois Tigeot S_0000F0_SOFT_RESET_GA(1));
478926deccbSFrançois Tigeot RREG32(R_0000F0_RBBM_SOFT_RESET);
479c4ef309bSzrj mdelay(500);
480926deccbSFrançois Tigeot WREG32(R_0000F0_RBBM_SOFT_RESET, 0);
481c4ef309bSzrj mdelay(1);
482926deccbSFrançois Tigeot status = RREG32(R_000E40_RBBM_STATUS);
483926deccbSFrançois Tigeot dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
484926deccbSFrançois Tigeot /* reset CP */
485926deccbSFrançois Tigeot WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_CP(1));
486926deccbSFrançois Tigeot RREG32(R_0000F0_RBBM_SOFT_RESET);
487c4ef309bSzrj mdelay(500);
488926deccbSFrançois Tigeot WREG32(R_0000F0_RBBM_SOFT_RESET, 0);
489c4ef309bSzrj mdelay(1);
490926deccbSFrançois Tigeot status = RREG32(R_000E40_RBBM_STATUS);
491926deccbSFrançois Tigeot dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
492926deccbSFrançois Tigeot /* reset MC */
493926deccbSFrançois Tigeot WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_MC(1));
494926deccbSFrançois Tigeot RREG32(R_0000F0_RBBM_SOFT_RESET);
495c4ef309bSzrj mdelay(500);
496926deccbSFrançois Tigeot WREG32(R_0000F0_RBBM_SOFT_RESET, 0);
497c4ef309bSzrj mdelay(1);
498926deccbSFrançois Tigeot status = RREG32(R_000E40_RBBM_STATUS);
499926deccbSFrançois Tigeot dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
500926deccbSFrançois Tigeot /* restore PCI & busmastering */
501fb572d17SFrançois Tigeot pci_restore_state(device_get_parent(rdev->dev->bsddev));
502926deccbSFrançois Tigeot /* Check if GPU is idle */
503926deccbSFrançois Tigeot if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) {
504926deccbSFrançois Tigeot dev_err(rdev->dev, "failed to reset GPU\n");
505926deccbSFrançois Tigeot ret = -1;
506926deccbSFrançois Tigeot } else
507926deccbSFrançois Tigeot dev_info(rdev->dev, "GPU reset succeed\n");
508926deccbSFrançois Tigeot rv515_mc_resume(rdev, &save);
509926deccbSFrançois Tigeot return ret;
510926deccbSFrançois Tigeot }
511926deccbSFrançois Tigeot
512926deccbSFrançois Tigeot /*
513926deccbSFrançois Tigeot * GART.
514926deccbSFrançois Tigeot */
rs600_gart_tlb_flush(struct radeon_device * rdev)515926deccbSFrançois Tigeot void rs600_gart_tlb_flush(struct radeon_device *rdev)
516926deccbSFrançois Tigeot {
517926deccbSFrançois Tigeot uint32_t tmp;
518926deccbSFrançois Tigeot
519926deccbSFrançois Tigeot tmp = RREG32_MC(R_000100_MC_PT0_CNTL);
520926deccbSFrançois Tigeot tmp &= C_000100_INVALIDATE_ALL_L1_TLBS & C_000100_INVALIDATE_L2_CACHE;
521926deccbSFrançois Tigeot WREG32_MC(R_000100_MC_PT0_CNTL, tmp);
522926deccbSFrançois Tigeot
523926deccbSFrançois Tigeot tmp = RREG32_MC(R_000100_MC_PT0_CNTL);
524926deccbSFrançois Tigeot tmp |= S_000100_INVALIDATE_ALL_L1_TLBS(1) | S_000100_INVALIDATE_L2_CACHE(1);
525926deccbSFrançois Tigeot WREG32_MC(R_000100_MC_PT0_CNTL, tmp);
526926deccbSFrançois Tigeot
527926deccbSFrançois Tigeot tmp = RREG32_MC(R_000100_MC_PT0_CNTL);
528926deccbSFrançois Tigeot tmp &= C_000100_INVALIDATE_ALL_L1_TLBS & C_000100_INVALIDATE_L2_CACHE;
529926deccbSFrançois Tigeot WREG32_MC(R_000100_MC_PT0_CNTL, tmp);
530926deccbSFrançois Tigeot tmp = RREG32_MC(R_000100_MC_PT0_CNTL);
531926deccbSFrançois Tigeot }
532926deccbSFrançois Tigeot
rs600_gart_init(struct radeon_device * rdev)533926deccbSFrançois Tigeot static int rs600_gart_init(struct radeon_device *rdev)
534926deccbSFrançois Tigeot {
535926deccbSFrançois Tigeot int r;
536926deccbSFrançois Tigeot
537926deccbSFrançois Tigeot if (rdev->gart.robj) {
538c4ef309bSzrj WARN(1, "RS600 GART already initialized\n");
539926deccbSFrançois Tigeot return 0;
540926deccbSFrançois Tigeot }
541926deccbSFrançois Tigeot /* Initialize common gart structure */
542926deccbSFrançois Tigeot r = radeon_gart_init(rdev);
543926deccbSFrançois Tigeot if (r) {
544926deccbSFrançois Tigeot return r;
545926deccbSFrançois Tigeot }
546926deccbSFrançois Tigeot rdev->gart.table_size = rdev->gart.num_gpu_pages * 8;
547926deccbSFrançois Tigeot return radeon_gart_table_vram_alloc(rdev);
548926deccbSFrançois Tigeot }
549926deccbSFrançois Tigeot
rs600_gart_enable(struct radeon_device * rdev)550926deccbSFrançois Tigeot static int rs600_gart_enable(struct radeon_device *rdev)
551926deccbSFrançois Tigeot {
552926deccbSFrançois Tigeot u32 tmp;
553926deccbSFrançois Tigeot int r, i;
554926deccbSFrançois Tigeot
555926deccbSFrançois Tigeot if (rdev->gart.robj == NULL) {
556926deccbSFrançois Tigeot dev_err(rdev->dev, "No VRAM object for PCIE GART.\n");
557926deccbSFrançois Tigeot return -EINVAL;
558926deccbSFrançois Tigeot }
559926deccbSFrançois Tigeot r = radeon_gart_table_vram_pin(rdev);
560926deccbSFrançois Tigeot if (r)
561926deccbSFrançois Tigeot return r;
562926deccbSFrançois Tigeot /* Enable bus master */
563926deccbSFrançois Tigeot tmp = RREG32(RADEON_BUS_CNTL) & ~RS600_BUS_MASTER_DIS;
564926deccbSFrançois Tigeot WREG32(RADEON_BUS_CNTL, tmp);
565926deccbSFrançois Tigeot /* FIXME: setup default page */
566926deccbSFrançois Tigeot WREG32_MC(R_000100_MC_PT0_CNTL,
567926deccbSFrançois Tigeot (S_000100_EFFECTIVE_L2_CACHE_SIZE(6) |
568926deccbSFrançois Tigeot S_000100_EFFECTIVE_L2_QUEUE_SIZE(6)));
569926deccbSFrançois Tigeot
570926deccbSFrançois Tigeot for (i = 0; i < 19; i++) {
571926deccbSFrançois Tigeot WREG32_MC(R_00016C_MC_PT0_CLIENT0_CNTL + i,
572926deccbSFrançois Tigeot S_00016C_ENABLE_TRANSLATION_MODE_OVERRIDE(1) |
573926deccbSFrançois Tigeot S_00016C_SYSTEM_ACCESS_MODE_MASK(
574926deccbSFrançois Tigeot V_00016C_SYSTEM_ACCESS_MODE_NOT_IN_SYS) |
575926deccbSFrançois Tigeot S_00016C_SYSTEM_APERTURE_UNMAPPED_ACCESS(
576926deccbSFrançois Tigeot V_00016C_SYSTEM_APERTURE_UNMAPPED_PASSTHROUGH) |
577926deccbSFrançois Tigeot S_00016C_EFFECTIVE_L1_CACHE_SIZE(3) |
578926deccbSFrançois Tigeot S_00016C_ENABLE_FRAGMENT_PROCESSING(1) |
579926deccbSFrançois Tigeot S_00016C_EFFECTIVE_L1_QUEUE_SIZE(3));
580926deccbSFrançois Tigeot }
581926deccbSFrançois Tigeot /* enable first context */
582926deccbSFrançois Tigeot WREG32_MC(R_000102_MC_PT0_CONTEXT0_CNTL,
583926deccbSFrançois Tigeot S_000102_ENABLE_PAGE_TABLE(1) |
584926deccbSFrançois Tigeot S_000102_PAGE_TABLE_DEPTH(V_000102_PAGE_TABLE_FLAT));
585926deccbSFrançois Tigeot
586926deccbSFrançois Tigeot /* disable all other contexts */
587926deccbSFrançois Tigeot for (i = 1; i < 8; i++)
588926deccbSFrançois Tigeot WREG32_MC(R_000102_MC_PT0_CONTEXT0_CNTL + i, 0);
589926deccbSFrançois Tigeot
590926deccbSFrançois Tigeot /* setup the page table */
591926deccbSFrançois Tigeot WREG32_MC(R_00012C_MC_PT0_CONTEXT0_FLAT_BASE_ADDR,
592926deccbSFrançois Tigeot rdev->gart.table_addr);
593926deccbSFrançois Tigeot WREG32_MC(R_00013C_MC_PT0_CONTEXT0_FLAT_START_ADDR, rdev->mc.gtt_start);
594926deccbSFrançois Tigeot WREG32_MC(R_00014C_MC_PT0_CONTEXT0_FLAT_END_ADDR, rdev->mc.gtt_end);
595926deccbSFrançois Tigeot WREG32_MC(R_00011C_MC_PT0_CONTEXT0_DEFAULT_READ_ADDR, 0);
596926deccbSFrançois Tigeot
597926deccbSFrançois Tigeot /* System context maps to VRAM space */
598926deccbSFrançois Tigeot WREG32_MC(R_000112_MC_PT0_SYSTEM_APERTURE_LOW_ADDR, rdev->mc.vram_start);
599926deccbSFrançois Tigeot WREG32_MC(R_000114_MC_PT0_SYSTEM_APERTURE_HIGH_ADDR, rdev->mc.vram_end);
600926deccbSFrançois Tigeot
601926deccbSFrançois Tigeot /* enable page tables */
602926deccbSFrançois Tigeot tmp = RREG32_MC(R_000100_MC_PT0_CNTL);
603926deccbSFrançois Tigeot WREG32_MC(R_000100_MC_PT0_CNTL, (tmp | S_000100_ENABLE_PT(1)));
604926deccbSFrançois Tigeot tmp = RREG32_MC(R_000009_MC_CNTL1);
605926deccbSFrançois Tigeot WREG32_MC(R_000009_MC_CNTL1, (tmp | S_000009_ENABLE_PAGE_TABLES(1)));
606926deccbSFrançois Tigeot rs600_gart_tlb_flush(rdev);
607926deccbSFrançois Tigeot DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n",
608926deccbSFrançois Tigeot (unsigned)(rdev->mc.gtt_size >> 20),
609926deccbSFrançois Tigeot (unsigned long long)rdev->gart.table_addr);
610926deccbSFrançois Tigeot rdev->gart.ready = true;
611926deccbSFrançois Tigeot return 0;
612926deccbSFrançois Tigeot }
613926deccbSFrançois Tigeot
rs600_gart_disable(struct radeon_device * rdev)614926deccbSFrançois Tigeot static void rs600_gart_disable(struct radeon_device *rdev)
615926deccbSFrançois Tigeot {
616926deccbSFrançois Tigeot u32 tmp;
617926deccbSFrançois Tigeot
618926deccbSFrançois Tigeot /* FIXME: disable out of gart access */
619926deccbSFrançois Tigeot WREG32_MC(R_000100_MC_PT0_CNTL, 0);
620926deccbSFrançois Tigeot tmp = RREG32_MC(R_000009_MC_CNTL1);
621926deccbSFrançois Tigeot WREG32_MC(R_000009_MC_CNTL1, tmp & C_000009_ENABLE_PAGE_TABLES);
622926deccbSFrançois Tigeot radeon_gart_table_vram_unpin(rdev);
623926deccbSFrançois Tigeot }
624926deccbSFrançois Tigeot
rs600_gart_fini(struct radeon_device * rdev)625926deccbSFrançois Tigeot static void rs600_gart_fini(struct radeon_device *rdev)
626926deccbSFrançois Tigeot {
627926deccbSFrançois Tigeot radeon_gart_fini(rdev);
628926deccbSFrançois Tigeot rs600_gart_disable(rdev);
629926deccbSFrançois Tigeot radeon_gart_table_vram_free(rdev);
630926deccbSFrançois Tigeot }
631926deccbSFrançois Tigeot
rs600_gart_get_page_entry(uint64_t addr,uint32_t flags)6327dcf36dcSFrançois Tigeot uint64_t rs600_gart_get_page_entry(uint64_t addr, uint32_t flags)
633926deccbSFrançois Tigeot {
634926deccbSFrançois Tigeot addr = addr & 0xFFFFFFFFFFFFF000ULL;
635c6f73aabSFrançois Tigeot addr |= R600_PTE_SYSTEM;
636c6f73aabSFrançois Tigeot if (flags & RADEON_GART_PAGE_VALID)
637c6f73aabSFrançois Tigeot addr |= R600_PTE_VALID;
638c6f73aabSFrançois Tigeot if (flags & RADEON_GART_PAGE_READ)
639c6f73aabSFrançois Tigeot addr |= R600_PTE_READABLE;
640c6f73aabSFrançois Tigeot if (flags & RADEON_GART_PAGE_WRITE)
641c6f73aabSFrançois Tigeot addr |= R600_PTE_WRITEABLE;
642c6f73aabSFrançois Tigeot if (flags & RADEON_GART_PAGE_SNOOP)
643c6f73aabSFrançois Tigeot addr |= R600_PTE_SNOOPED;
6447dcf36dcSFrançois Tigeot return addr;
6457dcf36dcSFrançois Tigeot }
6467dcf36dcSFrançois Tigeot
rs600_gart_set_page(struct radeon_device * rdev,unsigned i,uint64_t entry)6477dcf36dcSFrançois Tigeot void rs600_gart_set_page(struct radeon_device *rdev, unsigned i,
6487dcf36dcSFrançois Tigeot uint64_t entry)
6497dcf36dcSFrançois Tigeot {
6507dcf36dcSFrançois Tigeot void __iomem *ptr = (void *)rdev->gart.ptr;
6517dcf36dcSFrançois Tigeot writeq(entry, (uint8_t *)ptr + (i * 8));
652926deccbSFrançois Tigeot }
653926deccbSFrançois Tigeot
rs600_irq_set(struct radeon_device * rdev)654926deccbSFrançois Tigeot int rs600_irq_set(struct radeon_device *rdev)
655926deccbSFrançois Tigeot {
656926deccbSFrançois Tigeot uint32_t tmp = 0;
657926deccbSFrançois Tigeot uint32_t mode_int = 0;
658926deccbSFrançois Tigeot u32 hpd1 = RREG32(R_007D08_DC_HOT_PLUG_DETECT1_INT_CONTROL) &
659926deccbSFrançois Tigeot ~S_007D08_DC_HOT_PLUG_DETECT1_INT_EN(1);
660926deccbSFrançois Tigeot u32 hpd2 = RREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL) &
661926deccbSFrançois Tigeot ~S_007D18_DC_HOT_PLUG_DETECT2_INT_EN(1);
662926deccbSFrançois Tigeot u32 hdmi0;
663926deccbSFrançois Tigeot if (ASIC_IS_DCE2(rdev))
664926deccbSFrançois Tigeot hdmi0 = RREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL) &
665926deccbSFrançois Tigeot ~S_007408_HDMI0_AZ_FORMAT_WTRIG_MASK(1);
666926deccbSFrançois Tigeot else
667926deccbSFrançois Tigeot hdmi0 = 0;
668926deccbSFrançois Tigeot
669926deccbSFrançois Tigeot if (!rdev->irq.installed) {
670c4ef309bSzrj WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
671926deccbSFrançois Tigeot WREG32(R_000040_GEN_INT_CNTL, 0);
672926deccbSFrançois Tigeot return -EINVAL;
673926deccbSFrançois Tigeot }
674926deccbSFrançois Tigeot if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {
675926deccbSFrançois Tigeot tmp |= S_000040_SW_INT_EN(1);
676926deccbSFrançois Tigeot }
677926deccbSFrançois Tigeot if (rdev->irq.crtc_vblank_int[0] ||
678926deccbSFrançois Tigeot atomic_read(&rdev->irq.pflip[0])) {
679926deccbSFrançois Tigeot mode_int |= S_006540_D1MODE_VBLANK_INT_MASK(1);
680926deccbSFrançois Tigeot }
681926deccbSFrançois Tigeot if (rdev->irq.crtc_vblank_int[1] ||
682926deccbSFrançois Tigeot atomic_read(&rdev->irq.pflip[1])) {
683926deccbSFrançois Tigeot mode_int |= S_006540_D2MODE_VBLANK_INT_MASK(1);
684926deccbSFrançois Tigeot }
685926deccbSFrançois Tigeot if (rdev->irq.hpd[0]) {
686926deccbSFrançois Tigeot hpd1 |= S_007D08_DC_HOT_PLUG_DETECT1_INT_EN(1);
687926deccbSFrançois Tigeot }
688926deccbSFrançois Tigeot if (rdev->irq.hpd[1]) {
689926deccbSFrançois Tigeot hpd2 |= S_007D18_DC_HOT_PLUG_DETECT2_INT_EN(1);
690926deccbSFrançois Tigeot }
691926deccbSFrançois Tigeot if (rdev->irq.afmt[0]) {
692926deccbSFrançois Tigeot hdmi0 |= S_007408_HDMI0_AZ_FORMAT_WTRIG_MASK(1);
693926deccbSFrançois Tigeot }
694926deccbSFrançois Tigeot WREG32(R_000040_GEN_INT_CNTL, tmp);
695926deccbSFrançois Tigeot WREG32(R_006540_DxMODE_INT_MASK, mode_int);
696926deccbSFrançois Tigeot WREG32(R_007D08_DC_HOT_PLUG_DETECT1_INT_CONTROL, hpd1);
697926deccbSFrançois Tigeot WREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL, hpd2);
698926deccbSFrançois Tigeot if (ASIC_IS_DCE2(rdev))
699926deccbSFrançois Tigeot WREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL, hdmi0);
7007dcf36dcSFrançois Tigeot
7017dcf36dcSFrançois Tigeot /* posting read */
7027dcf36dcSFrançois Tigeot RREG32(R_000040_GEN_INT_CNTL);
7037dcf36dcSFrançois Tigeot
704926deccbSFrançois Tigeot return 0;
705926deccbSFrançois Tigeot }
706926deccbSFrançois Tigeot
rs600_irq_ack(struct radeon_device * rdev)707926deccbSFrançois Tigeot static inline u32 rs600_irq_ack(struct radeon_device *rdev)
708926deccbSFrançois Tigeot {
709926deccbSFrançois Tigeot uint32_t irqs = RREG32(R_000044_GEN_INT_STATUS);
710926deccbSFrançois Tigeot uint32_t irq_mask = S_000044_SW_INT(1);
711926deccbSFrançois Tigeot u32 tmp;
712926deccbSFrançois Tigeot
713926deccbSFrançois Tigeot if (G_000044_DISPLAY_INT_STAT(irqs)) {
714926deccbSFrançois Tigeot rdev->irq.stat_regs.r500.disp_int = RREG32(R_007EDC_DISP_INTERRUPT_STATUS);
715926deccbSFrançois Tigeot if (G_007EDC_LB_D1_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) {
716926deccbSFrançois Tigeot WREG32(R_006534_D1MODE_VBLANK_STATUS,
717926deccbSFrançois Tigeot S_006534_D1MODE_VBLANK_ACK(1));
718926deccbSFrançois Tigeot }
719926deccbSFrançois Tigeot if (G_007EDC_LB_D2_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) {
720926deccbSFrançois Tigeot WREG32(R_006D34_D2MODE_VBLANK_STATUS,
721926deccbSFrançois Tigeot S_006D34_D2MODE_VBLANK_ACK(1));
722926deccbSFrançois Tigeot }
723926deccbSFrançois Tigeot if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) {
724926deccbSFrançois Tigeot tmp = RREG32(R_007D08_DC_HOT_PLUG_DETECT1_INT_CONTROL);
725926deccbSFrançois Tigeot tmp |= S_007D08_DC_HOT_PLUG_DETECT1_INT_ACK(1);
726926deccbSFrançois Tigeot WREG32(R_007D08_DC_HOT_PLUG_DETECT1_INT_CONTROL, tmp);
727926deccbSFrançois Tigeot }
728926deccbSFrançois Tigeot if (G_007EDC_DC_HOT_PLUG_DETECT2_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) {
729926deccbSFrançois Tigeot tmp = RREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL);
730926deccbSFrançois Tigeot tmp |= S_007D18_DC_HOT_PLUG_DETECT2_INT_ACK(1);
731926deccbSFrançois Tigeot WREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL, tmp);
732926deccbSFrançois Tigeot }
733926deccbSFrançois Tigeot } else {
734926deccbSFrançois Tigeot rdev->irq.stat_regs.r500.disp_int = 0;
735926deccbSFrançois Tigeot }
736926deccbSFrançois Tigeot
737926deccbSFrançois Tigeot if (ASIC_IS_DCE2(rdev)) {
738926deccbSFrançois Tigeot rdev->irq.stat_regs.r500.hdmi0_status = RREG32(R_007404_HDMI0_STATUS) &
739926deccbSFrançois Tigeot S_007404_HDMI0_AZ_FORMAT_WTRIG(1);
740926deccbSFrançois Tigeot if (G_007404_HDMI0_AZ_FORMAT_WTRIG(rdev->irq.stat_regs.r500.hdmi0_status)) {
741926deccbSFrançois Tigeot tmp = RREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL);
742926deccbSFrançois Tigeot tmp |= S_007408_HDMI0_AZ_FORMAT_WTRIG_ACK(1);
743926deccbSFrançois Tigeot WREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL, tmp);
744926deccbSFrançois Tigeot }
745926deccbSFrançois Tigeot } else
746926deccbSFrançois Tigeot rdev->irq.stat_regs.r500.hdmi0_status = 0;
747926deccbSFrançois Tigeot
748926deccbSFrançois Tigeot if (irqs) {
749926deccbSFrançois Tigeot WREG32(R_000044_GEN_INT_STATUS, irqs);
750926deccbSFrançois Tigeot }
751926deccbSFrançois Tigeot return irqs & irq_mask;
752926deccbSFrançois Tigeot }
753926deccbSFrançois Tigeot
rs600_irq_disable(struct radeon_device * rdev)754926deccbSFrançois Tigeot void rs600_irq_disable(struct radeon_device *rdev)
755926deccbSFrançois Tigeot {
756926deccbSFrançois Tigeot u32 hdmi0 = RREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL) &
757926deccbSFrançois Tigeot ~S_007408_HDMI0_AZ_FORMAT_WTRIG_MASK(1);
758926deccbSFrançois Tigeot WREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL, hdmi0);
759926deccbSFrançois Tigeot WREG32(R_000040_GEN_INT_CNTL, 0);
760926deccbSFrançois Tigeot WREG32(R_006540_DxMODE_INT_MASK, 0);
761926deccbSFrançois Tigeot /* Wait and acknowledge irq */
762c4ef309bSzrj mdelay(1);
763926deccbSFrançois Tigeot rs600_irq_ack(rdev);
764926deccbSFrançois Tigeot }
765926deccbSFrançois Tigeot
rs600_irq_process(struct radeon_device * rdev)766926deccbSFrançois Tigeot irqreturn_t rs600_irq_process(struct radeon_device *rdev)
767926deccbSFrançois Tigeot {
768926deccbSFrançois Tigeot u32 status, msi_rearm;
769926deccbSFrançois Tigeot bool queue_hotplug = false;
770926deccbSFrançois Tigeot bool queue_hdmi = false;
771926deccbSFrançois Tigeot
772926deccbSFrançois Tigeot status = rs600_irq_ack(rdev);
773926deccbSFrançois Tigeot if (!status &&
774926deccbSFrançois Tigeot !rdev->irq.stat_regs.r500.disp_int &&
775926deccbSFrançois Tigeot !rdev->irq.stat_regs.r500.hdmi0_status) {
776926deccbSFrançois Tigeot return IRQ_NONE;
777926deccbSFrançois Tigeot }
778926deccbSFrançois Tigeot while (status ||
779926deccbSFrançois Tigeot rdev->irq.stat_regs.r500.disp_int ||
780926deccbSFrançois Tigeot rdev->irq.stat_regs.r500.hdmi0_status) {
781926deccbSFrançois Tigeot /* SW interrupt */
782926deccbSFrançois Tigeot if (G_000044_SW_INT(status)) {
783926deccbSFrançois Tigeot radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
784926deccbSFrançois Tigeot }
785926deccbSFrançois Tigeot /* Vertical blank interrupts */
786926deccbSFrançois Tigeot if (G_007EDC_LB_D1_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) {
787926deccbSFrançois Tigeot if (rdev->irq.crtc_vblank_int[0]) {
788926deccbSFrançois Tigeot drm_handle_vblank(rdev->ddev, 0);
789926deccbSFrançois Tigeot rdev->pm.vblank_sync = true;
790c4ef309bSzrj wake_up(&rdev->irq.vblank_queue);
791926deccbSFrançois Tigeot }
792926deccbSFrançois Tigeot if (atomic_read(&rdev->irq.pflip[0]))
793c6f73aabSFrançois Tigeot radeon_crtc_handle_vblank(rdev, 0);
794926deccbSFrançois Tigeot }
795926deccbSFrançois Tigeot if (G_007EDC_LB_D2_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) {
796926deccbSFrançois Tigeot if (rdev->irq.crtc_vblank_int[1]) {
797926deccbSFrançois Tigeot drm_handle_vblank(rdev->ddev, 1);
798926deccbSFrançois Tigeot rdev->pm.vblank_sync = true;
799c4ef309bSzrj wake_up(&rdev->irq.vblank_queue);
800926deccbSFrançois Tigeot }
801926deccbSFrançois Tigeot if (atomic_read(&rdev->irq.pflip[1]))
802c6f73aabSFrançois Tigeot radeon_crtc_handle_vblank(rdev, 1);
803926deccbSFrançois Tigeot }
804926deccbSFrançois Tigeot if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) {
805926deccbSFrançois Tigeot queue_hotplug = true;
806926deccbSFrançois Tigeot DRM_DEBUG("HPD1\n");
807926deccbSFrançois Tigeot }
808926deccbSFrançois Tigeot if (G_007EDC_DC_HOT_PLUG_DETECT2_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) {
809926deccbSFrançois Tigeot queue_hotplug = true;
810926deccbSFrançois Tigeot DRM_DEBUG("HPD2\n");
811926deccbSFrançois Tigeot }
812926deccbSFrançois Tigeot if (G_007404_HDMI0_AZ_FORMAT_WTRIG(rdev->irq.stat_regs.r500.hdmi0_status)) {
813926deccbSFrançois Tigeot queue_hdmi = true;
814926deccbSFrançois Tigeot DRM_DEBUG("HDMI0\n");
815926deccbSFrançois Tigeot }
816926deccbSFrançois Tigeot status = rs600_irq_ack(rdev);
817926deccbSFrançois Tigeot }
818926deccbSFrançois Tigeot if (queue_hotplug)
819c59a5c48SFrançois Tigeot schedule_delayed_work(&rdev->hotplug_work, 0);
820926deccbSFrançois Tigeot if (queue_hdmi)
8212c5cc6b9SFrançois Tigeot schedule_work(&rdev->audio_work);
822926deccbSFrançois Tigeot if (rdev->msi_enabled) {
823926deccbSFrançois Tigeot switch (rdev->family) {
824926deccbSFrançois Tigeot case CHIP_RS600:
825926deccbSFrançois Tigeot case CHIP_RS690:
826926deccbSFrançois Tigeot case CHIP_RS740:
827926deccbSFrançois Tigeot msi_rearm = RREG32(RADEON_BUS_CNTL) & ~RS600_MSI_REARM;
828926deccbSFrançois Tigeot WREG32(RADEON_BUS_CNTL, msi_rearm);
829926deccbSFrançois Tigeot WREG32(RADEON_BUS_CNTL, msi_rearm | RS600_MSI_REARM);
830926deccbSFrançois Tigeot break;
831926deccbSFrançois Tigeot default:
832926deccbSFrançois Tigeot WREG32(RADEON_MSI_REARM_EN, RV370_MSI_REARM_EN);
833926deccbSFrançois Tigeot break;
834926deccbSFrançois Tigeot }
835926deccbSFrançois Tigeot }
836926deccbSFrançois Tigeot return IRQ_HANDLED;
837926deccbSFrançois Tigeot }
838926deccbSFrançois Tigeot
rs600_get_vblank_counter(struct radeon_device * rdev,int crtc)839926deccbSFrançois Tigeot u32 rs600_get_vblank_counter(struct radeon_device *rdev, int crtc)
840926deccbSFrançois Tigeot {
841926deccbSFrançois Tigeot if (crtc == 0)
842926deccbSFrançois Tigeot return RREG32(R_0060A4_D1CRTC_STATUS_FRAME_COUNT);
843926deccbSFrançois Tigeot else
844926deccbSFrançois Tigeot return RREG32(R_0068A4_D2CRTC_STATUS_FRAME_COUNT);
845926deccbSFrançois Tigeot }
846926deccbSFrançois Tigeot
rs600_mc_wait_for_idle(struct radeon_device * rdev)847926deccbSFrançois Tigeot int rs600_mc_wait_for_idle(struct radeon_device *rdev)
848926deccbSFrançois Tigeot {
849926deccbSFrançois Tigeot unsigned i;
850926deccbSFrançois Tigeot
851926deccbSFrançois Tigeot for (i = 0; i < rdev->usec_timeout; i++) {
852926deccbSFrançois Tigeot if (G_000000_MC_IDLE(RREG32_MC(R_000000_MC_STATUS)))
853926deccbSFrançois Tigeot return 0;
854c4ef309bSzrj udelay(1);
855926deccbSFrançois Tigeot }
856926deccbSFrançois Tigeot return -1;
857926deccbSFrançois Tigeot }
858926deccbSFrançois Tigeot
rs600_gpu_init(struct radeon_device * rdev)859926deccbSFrançois Tigeot static void rs600_gpu_init(struct radeon_device *rdev)
860926deccbSFrançois Tigeot {
861926deccbSFrançois Tigeot r420_pipes_init(rdev);
862926deccbSFrançois Tigeot /* Wait for mc idle */
863926deccbSFrançois Tigeot if (rs600_mc_wait_for_idle(rdev))
864926deccbSFrançois Tigeot dev_warn(rdev->dev, "Wait MC idle timeout before updating MC.\n");
865926deccbSFrançois Tigeot }
866926deccbSFrançois Tigeot
rs600_mc_init(struct radeon_device * rdev)867926deccbSFrançois Tigeot static void rs600_mc_init(struct radeon_device *rdev)
868926deccbSFrançois Tigeot {
869926deccbSFrançois Tigeot u64 base;
870926deccbSFrançois Tigeot
8714a26d795SImre Vadasz rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0);
8724a26d795SImre Vadasz rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0);
873926deccbSFrançois Tigeot rdev->mc.vram_is_ddr = true;
874926deccbSFrançois Tigeot rdev->mc.vram_width = 128;
875926deccbSFrançois Tigeot rdev->mc.real_vram_size = RREG32(RADEON_CONFIG_MEMSIZE);
876926deccbSFrançois Tigeot rdev->mc.mc_vram_size = rdev->mc.real_vram_size;
877926deccbSFrançois Tigeot rdev->mc.visible_vram_size = rdev->mc.aper_size;
878926deccbSFrançois Tigeot rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev);
879926deccbSFrançois Tigeot base = RREG32_MC(R_000004_MC_FB_LOCATION);
880926deccbSFrançois Tigeot base = G_000004_MC_FB_START(base) << 16;
881926deccbSFrançois Tigeot radeon_vram_location(rdev, &rdev->mc, base);
882926deccbSFrançois Tigeot rdev->mc.gtt_base_align = 0;
883926deccbSFrançois Tigeot radeon_gtt_location(rdev, &rdev->mc);
884926deccbSFrançois Tigeot radeon_update_bandwidth_info(rdev);
885926deccbSFrançois Tigeot }
886926deccbSFrançois Tigeot
rs600_bandwidth_update(struct radeon_device * rdev)887926deccbSFrançois Tigeot void rs600_bandwidth_update(struct radeon_device *rdev)
888926deccbSFrançois Tigeot {
889926deccbSFrançois Tigeot struct drm_display_mode *mode0 = NULL;
890926deccbSFrançois Tigeot struct drm_display_mode *mode1 = NULL;
891926deccbSFrançois Tigeot u32 d1mode_priority_a_cnt, d2mode_priority_a_cnt;
892926deccbSFrançois Tigeot /* FIXME: implement full support */
893926deccbSFrançois Tigeot
894591d5043SFrançois Tigeot if (!rdev->mode_info.mode_config_initialized)
895591d5043SFrançois Tigeot return;
896591d5043SFrançois Tigeot
897926deccbSFrançois Tigeot radeon_update_display_priority(rdev);
898926deccbSFrançois Tigeot
899926deccbSFrançois Tigeot if (rdev->mode_info.crtcs[0]->base.enabled)
900926deccbSFrançois Tigeot mode0 = &rdev->mode_info.crtcs[0]->base.mode;
901926deccbSFrançois Tigeot if (rdev->mode_info.crtcs[1]->base.enabled)
902926deccbSFrançois Tigeot mode1 = &rdev->mode_info.crtcs[1]->base.mode;
903926deccbSFrançois Tigeot
904926deccbSFrançois Tigeot rs690_line_buffer_adjust(rdev, mode0, mode1);
905926deccbSFrançois Tigeot
906926deccbSFrançois Tigeot if (rdev->disp_priority == 2) {
907926deccbSFrançois Tigeot d1mode_priority_a_cnt = RREG32(R_006548_D1MODE_PRIORITY_A_CNT);
908926deccbSFrançois Tigeot d2mode_priority_a_cnt = RREG32(R_006D48_D2MODE_PRIORITY_A_CNT);
909926deccbSFrançois Tigeot d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1);
910926deccbSFrançois Tigeot d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1);
911926deccbSFrançois Tigeot WREG32(R_006548_D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt);
912926deccbSFrançois Tigeot WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt);
913926deccbSFrançois Tigeot WREG32(R_006D48_D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt);
914926deccbSFrançois Tigeot WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt);
915926deccbSFrançois Tigeot }
916926deccbSFrançois Tigeot }
917926deccbSFrançois Tigeot
rs600_mc_rreg(struct radeon_device * rdev,uint32_t reg)918926deccbSFrançois Tigeot uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg)
919926deccbSFrançois Tigeot {
920c6f73aabSFrançois Tigeot u32 r;
921c6f73aabSFrançois Tigeot
922*ec5b6af4SFrançois Tigeot lockmgr(&rdev->mc_idx_lock, LK_EXCLUSIVE);
923926deccbSFrançois Tigeot WREG32(R_000070_MC_IND_INDEX, S_000070_MC_IND_ADDR(reg) |
924926deccbSFrançois Tigeot S_000070_MC_IND_CITF_ARB0(1));
925c6f73aabSFrançois Tigeot r = RREG32(R_000074_MC_IND_DATA);
926*ec5b6af4SFrançois Tigeot lockmgr(&rdev->mc_idx_lock, LK_RELEASE);
927c6f73aabSFrançois Tigeot return r;
928926deccbSFrançois Tigeot }
929926deccbSFrançois Tigeot
rs600_mc_wreg(struct radeon_device * rdev,uint32_t reg,uint32_t v)930926deccbSFrançois Tigeot void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
931926deccbSFrançois Tigeot {
932*ec5b6af4SFrançois Tigeot lockmgr(&rdev->mc_idx_lock, LK_EXCLUSIVE);
933926deccbSFrançois Tigeot WREG32(R_000070_MC_IND_INDEX, S_000070_MC_IND_ADDR(reg) |
934926deccbSFrançois Tigeot S_000070_MC_IND_CITF_ARB0(1) | S_000070_MC_IND_WR_EN(1));
935926deccbSFrançois Tigeot WREG32(R_000074_MC_IND_DATA, v);
936*ec5b6af4SFrançois Tigeot lockmgr(&rdev->mc_idx_lock, LK_RELEASE);
937926deccbSFrançois Tigeot }
938926deccbSFrançois Tigeot
rs600_debugfs(struct radeon_device * rdev)939926deccbSFrançois Tigeot static void rs600_debugfs(struct radeon_device *rdev)
940926deccbSFrançois Tigeot {
941926deccbSFrançois Tigeot if (r100_debugfs_rbbm_init(rdev))
942926deccbSFrançois Tigeot DRM_ERROR("Failed to register debugfs file for RBBM !\n");
943926deccbSFrançois Tigeot }
944926deccbSFrançois Tigeot
rs600_set_safe_registers(struct radeon_device * rdev)945926deccbSFrançois Tigeot void rs600_set_safe_registers(struct radeon_device *rdev)
946926deccbSFrançois Tigeot {
947926deccbSFrançois Tigeot rdev->config.r300.reg_safe_bm = rs600_reg_safe_bm;
948c4ef309bSzrj rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(rs600_reg_safe_bm);
949926deccbSFrançois Tigeot }
950926deccbSFrançois Tigeot
rs600_mc_program(struct radeon_device * rdev)951926deccbSFrançois Tigeot static void rs600_mc_program(struct radeon_device *rdev)
952926deccbSFrançois Tigeot {
953926deccbSFrançois Tigeot struct rv515_mc_save save;
954926deccbSFrançois Tigeot
955926deccbSFrançois Tigeot /* Stops all mc clients */
956926deccbSFrançois Tigeot rv515_mc_stop(rdev, &save);
957926deccbSFrançois Tigeot
958926deccbSFrançois Tigeot /* Wait for mc idle */
959926deccbSFrançois Tigeot if (rs600_mc_wait_for_idle(rdev))
960926deccbSFrançois Tigeot dev_warn(rdev->dev, "Wait MC idle timeout before updating MC.\n");
961926deccbSFrançois Tigeot
962926deccbSFrançois Tigeot /* FIXME: What does AGP means for such chipset ? */
963926deccbSFrançois Tigeot WREG32_MC(R_000005_MC_AGP_LOCATION, 0x0FFFFFFF);
964926deccbSFrançois Tigeot WREG32_MC(R_000006_AGP_BASE, 0);
965926deccbSFrançois Tigeot WREG32_MC(R_000007_AGP_BASE_2, 0);
966926deccbSFrançois Tigeot /* Program MC */
967926deccbSFrançois Tigeot WREG32_MC(R_000004_MC_FB_LOCATION,
968926deccbSFrançois Tigeot S_000004_MC_FB_START(rdev->mc.vram_start >> 16) |
969926deccbSFrançois Tigeot S_000004_MC_FB_TOP(rdev->mc.vram_end >> 16));
970926deccbSFrançois Tigeot WREG32(R_000134_HDP_FB_LOCATION,
971926deccbSFrançois Tigeot S_000134_HDP_FB_START(rdev->mc.vram_start >> 16));
972926deccbSFrançois Tigeot
973926deccbSFrançois Tigeot rv515_mc_resume(rdev, &save);
974926deccbSFrançois Tigeot }
975926deccbSFrançois Tigeot
rs600_startup(struct radeon_device * rdev)976926deccbSFrançois Tigeot static int rs600_startup(struct radeon_device *rdev)
977926deccbSFrançois Tigeot {
978926deccbSFrançois Tigeot int r;
979926deccbSFrançois Tigeot
980926deccbSFrançois Tigeot rs600_mc_program(rdev);
981926deccbSFrançois Tigeot /* Resume clock */
982926deccbSFrançois Tigeot rv515_clock_startup(rdev);
983926deccbSFrançois Tigeot /* Initialize GPU configuration (# pipes, ...) */
984926deccbSFrançois Tigeot rs600_gpu_init(rdev);
985926deccbSFrançois Tigeot /* Initialize GART (initialize after TTM so we can allocate
986926deccbSFrançois Tigeot * memory through TTM but finalize after TTM) */
987926deccbSFrançois Tigeot r = rs600_gart_enable(rdev);
988926deccbSFrançois Tigeot if (r)
989926deccbSFrançois Tigeot return r;
990926deccbSFrançois Tigeot
991926deccbSFrançois Tigeot /* allocate wb buffer */
992926deccbSFrançois Tigeot r = radeon_wb_init(rdev);
993926deccbSFrançois Tigeot if (r)
994926deccbSFrançois Tigeot return r;
995926deccbSFrançois Tigeot
996926deccbSFrançois Tigeot r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX);
997926deccbSFrançois Tigeot if (r) {
998926deccbSFrançois Tigeot dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
999926deccbSFrançois Tigeot return r;
1000926deccbSFrançois Tigeot }
1001926deccbSFrançois Tigeot
1002926deccbSFrançois Tigeot /* Enable IRQ */
1003f43cf1b1SMichael Neumann if (!rdev->irq.installed) {
1004f43cf1b1SMichael Neumann r = radeon_irq_kms_init(rdev);
1005f43cf1b1SMichael Neumann if (r)
1006f43cf1b1SMichael Neumann return r;
1007f43cf1b1SMichael Neumann }
1008f43cf1b1SMichael Neumann
1009926deccbSFrançois Tigeot rs600_irq_set(rdev);
1010926deccbSFrançois Tigeot rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
1011926deccbSFrançois Tigeot /* 1M ring buffer */
1012926deccbSFrançois Tigeot r = r100_cp_init(rdev, 1024 * 1024);
1013926deccbSFrançois Tigeot if (r) {
1014926deccbSFrançois Tigeot dev_err(rdev->dev, "failed initializing CP (%d).\n", r);
1015926deccbSFrançois Tigeot return r;
1016926deccbSFrançois Tigeot }
1017926deccbSFrançois Tigeot
1018926deccbSFrançois Tigeot r = radeon_ib_pool_init(rdev);
1019926deccbSFrançois Tigeot if (r) {
1020926deccbSFrançois Tigeot dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
1021926deccbSFrançois Tigeot return r;
1022926deccbSFrançois Tigeot }
1023926deccbSFrançois Tigeot
1024c59a5c48SFrançois Tigeot r = radeon_audio_init(rdev);
1025926deccbSFrançois Tigeot if (r) {
1026926deccbSFrançois Tigeot dev_err(rdev->dev, "failed initializing audio\n");
1027926deccbSFrançois Tigeot return r;
1028926deccbSFrançois Tigeot }
1029926deccbSFrançois Tigeot
1030926deccbSFrançois Tigeot return 0;
1031926deccbSFrançois Tigeot }
1032926deccbSFrançois Tigeot
rs600_resume(struct radeon_device * rdev)1033926deccbSFrançois Tigeot int rs600_resume(struct radeon_device *rdev)
1034926deccbSFrançois Tigeot {
1035926deccbSFrançois Tigeot int r;
1036926deccbSFrançois Tigeot
1037926deccbSFrançois Tigeot /* Make sur GART are not working */
1038926deccbSFrançois Tigeot rs600_gart_disable(rdev);
1039926deccbSFrançois Tigeot /* Resume clock before doing reset */
1040926deccbSFrançois Tigeot rv515_clock_startup(rdev);
1041926deccbSFrançois Tigeot /* Reset gpu before posting otherwise ATOM will enter infinite loop */
1042926deccbSFrançois Tigeot if (radeon_asic_reset(rdev)) {
1043926deccbSFrançois Tigeot dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
1044926deccbSFrançois Tigeot RREG32(R_000E40_RBBM_STATUS),
1045926deccbSFrançois Tigeot RREG32(R_0007C0_CP_STAT));
1046926deccbSFrançois Tigeot }
1047926deccbSFrançois Tigeot /* post */
1048926deccbSFrançois Tigeot atom_asic_init(rdev->mode_info.atom_context);
1049926deccbSFrançois Tigeot /* Resume clock after posting */
1050926deccbSFrançois Tigeot rv515_clock_startup(rdev);
1051926deccbSFrançois Tigeot /* Initialize surface registers */
1052926deccbSFrançois Tigeot radeon_surface_init(rdev);
1053926deccbSFrançois Tigeot
1054926deccbSFrançois Tigeot rdev->accel_working = true;
1055926deccbSFrançois Tigeot r = rs600_startup(rdev);
1056926deccbSFrançois Tigeot if (r) {
1057926deccbSFrançois Tigeot rdev->accel_working = false;
1058926deccbSFrançois Tigeot }
1059926deccbSFrançois Tigeot return r;
1060926deccbSFrançois Tigeot }
1061926deccbSFrançois Tigeot
rs600_suspend(struct radeon_device * rdev)1062926deccbSFrançois Tigeot int rs600_suspend(struct radeon_device *rdev)
1063926deccbSFrançois Tigeot {
1064c6f73aabSFrançois Tigeot radeon_pm_suspend(rdev);
1065c59a5c48SFrançois Tigeot radeon_audio_fini(rdev);
1066926deccbSFrançois Tigeot r100_cp_disable(rdev);
1067926deccbSFrançois Tigeot radeon_wb_disable(rdev);
1068926deccbSFrançois Tigeot rs600_irq_disable(rdev);
1069926deccbSFrançois Tigeot rs600_gart_disable(rdev);
1070926deccbSFrançois Tigeot return 0;
1071926deccbSFrançois Tigeot }
1072926deccbSFrançois Tigeot
rs600_fini(struct radeon_device * rdev)1073926deccbSFrançois Tigeot void rs600_fini(struct radeon_device *rdev)
1074926deccbSFrançois Tigeot {
1075c6f73aabSFrançois Tigeot radeon_pm_fini(rdev);
1076c59a5c48SFrançois Tigeot radeon_audio_fini(rdev);
1077926deccbSFrançois Tigeot r100_cp_fini(rdev);
1078926deccbSFrançois Tigeot radeon_wb_fini(rdev);
1079926deccbSFrançois Tigeot radeon_ib_pool_fini(rdev);
1080926deccbSFrançois Tigeot radeon_gem_fini(rdev);
1081926deccbSFrançois Tigeot rs600_gart_fini(rdev);
1082926deccbSFrançois Tigeot radeon_irq_kms_fini(rdev);
1083926deccbSFrançois Tigeot radeon_fence_driver_fini(rdev);
1084926deccbSFrançois Tigeot radeon_bo_fini(rdev);
1085926deccbSFrançois Tigeot radeon_atombios_fini(rdev);
1086c4ef309bSzrj kfree(rdev->bios);
1087926deccbSFrançois Tigeot rdev->bios = NULL;
1088926deccbSFrançois Tigeot }
1089926deccbSFrançois Tigeot
rs600_init(struct radeon_device * rdev)1090926deccbSFrançois Tigeot int rs600_init(struct radeon_device *rdev)
1091926deccbSFrançois Tigeot {
1092926deccbSFrançois Tigeot int r;
1093926deccbSFrançois Tigeot
1094926deccbSFrançois Tigeot /* Disable VGA */
1095926deccbSFrançois Tigeot rv515_vga_render_disable(rdev);
1096926deccbSFrançois Tigeot /* Initialize scratch registers */
1097926deccbSFrançois Tigeot radeon_scratch_init(rdev);
1098926deccbSFrançois Tigeot /* Initialize surface registers */
1099926deccbSFrançois Tigeot radeon_surface_init(rdev);
1100926deccbSFrançois Tigeot /* restore some register to sane defaults */
1101926deccbSFrançois Tigeot r100_restore_sanity(rdev);
1102926deccbSFrançois Tigeot /* BIOS */
1103926deccbSFrançois Tigeot if (!radeon_get_bios(rdev)) {
1104926deccbSFrançois Tigeot if (ASIC_IS_AVIVO(rdev))
1105926deccbSFrançois Tigeot return -EINVAL;
1106926deccbSFrançois Tigeot }
1107926deccbSFrançois Tigeot if (rdev->is_atom_bios) {
1108926deccbSFrançois Tigeot r = radeon_atombios_init(rdev);
1109926deccbSFrançois Tigeot if (r)
1110926deccbSFrançois Tigeot return r;
1111926deccbSFrançois Tigeot } else {
1112926deccbSFrançois Tigeot dev_err(rdev->dev, "Expecting atombios for RS600 GPU\n");
1113926deccbSFrançois Tigeot return -EINVAL;
1114926deccbSFrançois Tigeot }
1115926deccbSFrançois Tigeot /* Reset gpu before posting otherwise ATOM will enter infinite loop */
1116926deccbSFrançois Tigeot if (radeon_asic_reset(rdev)) {
1117926deccbSFrançois Tigeot dev_warn(rdev->dev,
1118926deccbSFrançois Tigeot "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
1119926deccbSFrançois Tigeot RREG32(R_000E40_RBBM_STATUS),
1120926deccbSFrançois Tigeot RREG32(R_0007C0_CP_STAT));
1121926deccbSFrançois Tigeot }
1122926deccbSFrançois Tigeot /* check if cards are posted or not */
1123926deccbSFrançois Tigeot if (radeon_boot_test_post_card(rdev) == false)
1124926deccbSFrançois Tigeot return -EINVAL;
1125926deccbSFrançois Tigeot
1126926deccbSFrançois Tigeot /* Initialize clocks */
1127926deccbSFrançois Tigeot radeon_get_clock_info(rdev->ddev);
1128926deccbSFrançois Tigeot /* initialize memory controller */
1129926deccbSFrançois Tigeot rs600_mc_init(rdev);
1130926deccbSFrançois Tigeot rs600_debugfs(rdev);
1131926deccbSFrançois Tigeot /* Fence driver */
1132926deccbSFrançois Tigeot r = radeon_fence_driver_init(rdev);
1133926deccbSFrançois Tigeot if (r)
1134926deccbSFrançois Tigeot return r;
1135926deccbSFrançois Tigeot /* Memory manager */
1136926deccbSFrançois Tigeot r = radeon_bo_init(rdev);
1137926deccbSFrançois Tigeot if (r)
1138926deccbSFrançois Tigeot return r;
1139926deccbSFrançois Tigeot r = rs600_gart_init(rdev);
1140926deccbSFrançois Tigeot if (r)
1141926deccbSFrançois Tigeot return r;
1142926deccbSFrançois Tigeot rs600_set_safe_registers(rdev);
1143926deccbSFrançois Tigeot
1144c6f73aabSFrançois Tigeot /* Initialize power management */
1145c6f73aabSFrançois Tigeot radeon_pm_init(rdev);
1146c6f73aabSFrançois Tigeot
1147926deccbSFrançois Tigeot rdev->accel_working = true;
1148926deccbSFrançois Tigeot r = rs600_startup(rdev);
1149926deccbSFrançois Tigeot if (r) {
1150926deccbSFrançois Tigeot /* Somethings want wront with the accel init stop accel */
1151926deccbSFrançois Tigeot dev_err(rdev->dev, "Disabling GPU acceleration\n");
1152926deccbSFrançois Tigeot r100_cp_fini(rdev);
1153926deccbSFrançois Tigeot radeon_wb_fini(rdev);
1154926deccbSFrançois Tigeot radeon_ib_pool_fini(rdev);
1155926deccbSFrançois Tigeot rs600_gart_fini(rdev);
1156926deccbSFrançois Tigeot radeon_irq_kms_fini(rdev);
1157926deccbSFrançois Tigeot rdev->accel_working = false;
1158926deccbSFrançois Tigeot }
1159926deccbSFrançois Tigeot return 0;
1160926deccbSFrançois Tigeot }
1161