Linux Audio

Check our new training course

Linux BSP development engineering services

Need help to port Linux and bootloaders to your hardware?
Loading...
v3.1
  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 */
 28#include "drmP.h"
 29#include "drm_crtc_helper.h"
 30#include "radeon_drm.h"
 31#include "radeon_reg.h"
 32#include "radeon.h"
 33#include "atom.h"
 34
 35irqreturn_t radeon_driver_irq_handler_kms(DRM_IRQ_ARGS)
 36{
 37	struct drm_device *dev = (struct drm_device *) arg;
 38	struct radeon_device *rdev = dev->dev_private;
 39
 40	return radeon_irq_process(rdev);
 41}
 42
 43/*
 44 * Handle hotplug events outside the interrupt handler proper.
 45 */
 46static void radeon_hotplug_work_func(struct work_struct *work)
 47{
 48	struct radeon_device *rdev = container_of(work, struct radeon_device,
 49						  hotplug_work);
 50	struct drm_device *dev = rdev->ddev;
 51	struct drm_mode_config *mode_config = &dev->mode_config;
 52	struct drm_connector *connector;
 53
 54	if (mode_config->num_connector) {
 55		list_for_each_entry(connector, &mode_config->connector_list, head)
 56			radeon_connector_hotplug(connector);
 57	}
 58	/* Just fire off a uevent and let userspace tell us what to do */
 59	drm_helper_hpd_irq_event(dev);
 60}
 61
 62void radeon_driver_irq_preinstall_kms(struct drm_device *dev)
 63{
 64	struct radeon_device *rdev = dev->dev_private;
 65	unsigned i;
 66
 67	/* Disable *all* interrupts */
 68	rdev->irq.sw_int = false;
 
 69	rdev->irq.gui_idle = false;
 70	for (i = 0; i < rdev->num_crtc; i++)
 71		rdev->irq.crtc_vblank_int[i] = false;
 72	for (i = 0; i < 6; i++) {
 73		rdev->irq.hpd[i] = false;
 
 
 74		rdev->irq.pflip[i] = false;
 
 75	}
 76	radeon_irq_set(rdev);
 77	/* Clear bits */
 78	radeon_irq_process(rdev);
 79}
 80
 81int radeon_driver_irq_postinstall_kms(struct drm_device *dev)
 82{
 83	struct radeon_device *rdev = dev->dev_private;
 
 84
 85	dev->max_vblank_count = 0x001fffff;
 86	rdev->irq.sw_int = true;
 
 87	radeon_irq_set(rdev);
 88	return 0;
 89}
 90
 91void radeon_driver_irq_uninstall_kms(struct drm_device *dev)
 92{
 93	struct radeon_device *rdev = dev->dev_private;
 94	unsigned i;
 95
 96	if (rdev == NULL) {
 97		return;
 98	}
 99	/* Disable *all* interrupts */
100	rdev->irq.sw_int = false;
 
101	rdev->irq.gui_idle = false;
102	for (i = 0; i < rdev->num_crtc; i++)
103		rdev->irq.crtc_vblank_int[i] = false;
104	for (i = 0; i < 6; i++) {
105		rdev->irq.hpd[i] = false;
 
 
106		rdev->irq.pflip[i] = false;
 
107	}
108	radeon_irq_set(rdev);
109}
110
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111int radeon_irq_kms_init(struct radeon_device *rdev)
112{
113	int i;
114	int r = 0;
115
116	INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
 
117
118	spin_lock_init(&rdev->irq.sw_lock);
119	for (i = 0; i < rdev->num_crtc; i++)
120		spin_lock_init(&rdev->irq.pflip_lock[i]);
121	r = drm_vblank_init(rdev->ddev, rdev->num_crtc);
122	if (r) {
123		return r;
124	}
125	/* enable msi */
126	rdev->msi_enabled = 0;
127	/* MSIs don't seem to work reliably on all IGP
128	 * chips.  Disable MSI on them for now.
129	 */
130	if ((rdev->family >= CHIP_RV380) &&
131	    ((!(rdev->flags & RADEON_IS_IGP)) || (rdev->family >= CHIP_PALM)) &&
132	    (!(rdev->flags & RADEON_IS_AGP))) {
133		int ret = pci_enable_msi(rdev->pdev);
134		if (!ret) {
135			rdev->msi_enabled = 1;
136			dev_info(rdev->dev, "radeon: using MSI.\n");
137		}
138	}
139	rdev->irq.installed = true;
140	r = drm_irq_install(rdev->ddev);
141	if (r) {
142		rdev->irq.installed = false;
143		return r;
144	}
145	DRM_INFO("radeon: irq initialized.\n");
146	return 0;
147}
148
149void radeon_irq_kms_fini(struct radeon_device *rdev)
150{
151	drm_vblank_cleanup(rdev->ddev);
152	if (rdev->irq.installed) {
153		drm_irq_uninstall(rdev->ddev);
154		rdev->irq.installed = false;
155		if (rdev->msi_enabled)
156			pci_disable_msi(rdev->pdev);
157	}
158	flush_work_sync(&rdev->hotplug_work);
159}
160
161void radeon_irq_kms_sw_irq_get(struct radeon_device *rdev)
162{
163	unsigned long irqflags;
164
165	spin_lock_irqsave(&rdev->irq.sw_lock, irqflags);
166	if (rdev->ddev->irq_enabled && (++rdev->irq.sw_refcount == 1)) {
167		rdev->irq.sw_int = true;
168		radeon_irq_set(rdev);
169	}
170	spin_unlock_irqrestore(&rdev->irq.sw_lock, irqflags);
171}
172
173void radeon_irq_kms_sw_irq_put(struct radeon_device *rdev)
174{
175	unsigned long irqflags;
176
177	spin_lock_irqsave(&rdev->irq.sw_lock, irqflags);
178	BUG_ON(rdev->ddev->irq_enabled && rdev->irq.sw_refcount <= 0);
179	if (rdev->ddev->irq_enabled && (--rdev->irq.sw_refcount == 0)) {
180		rdev->irq.sw_int = false;
181		radeon_irq_set(rdev);
182	}
183	spin_unlock_irqrestore(&rdev->irq.sw_lock, irqflags);
184}
185
186void radeon_irq_kms_pflip_irq_get(struct radeon_device *rdev, int crtc)
187{
188	unsigned long irqflags;
189
190	if (crtc < 0 || crtc >= rdev->num_crtc)
191		return;
192
193	spin_lock_irqsave(&rdev->irq.pflip_lock[crtc], irqflags);
194	if (rdev->ddev->irq_enabled && (++rdev->irq.pflip_refcount[crtc] == 1)) {
195		rdev->irq.pflip[crtc] = true;
196		radeon_irq_set(rdev);
197	}
198	spin_unlock_irqrestore(&rdev->irq.pflip_lock[crtc], irqflags);
199}
200
201void radeon_irq_kms_pflip_irq_put(struct radeon_device *rdev, int crtc)
202{
203	unsigned long irqflags;
204
205	if (crtc < 0 || crtc >= rdev->num_crtc)
206		return;
207
208	spin_lock_irqsave(&rdev->irq.pflip_lock[crtc], irqflags);
209	BUG_ON(rdev->ddev->irq_enabled && rdev->irq.pflip_refcount[crtc] <= 0);
210	if (rdev->ddev->irq_enabled && (--rdev->irq.pflip_refcount[crtc] == 0)) {
211		rdev->irq.pflip[crtc] = false;
212		radeon_irq_set(rdev);
213	}
214	spin_unlock_irqrestore(&rdev->irq.pflip_lock[crtc], irqflags);
215}
216
v3.5.6
  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 */
 28#include "drmP.h"
 29#include "drm_crtc_helper.h"
 30#include "radeon_drm.h"
 31#include "radeon_reg.h"
 32#include "radeon.h"
 33#include "atom.h"
 34
 35irqreturn_t radeon_driver_irq_handler_kms(DRM_IRQ_ARGS)
 36{
 37	struct drm_device *dev = (struct drm_device *) arg;
 38	struct radeon_device *rdev = dev->dev_private;
 39
 40	return radeon_irq_process(rdev);
 41}
 42
 43/*
 44 * Handle hotplug events outside the interrupt handler proper.
 45 */
 46static void radeon_hotplug_work_func(struct work_struct *work)
 47{
 48	struct radeon_device *rdev = container_of(work, struct radeon_device,
 49						  hotplug_work);
 50	struct drm_device *dev = rdev->ddev;
 51	struct drm_mode_config *mode_config = &dev->mode_config;
 52	struct drm_connector *connector;
 53
 54	if (mode_config->num_connector) {
 55		list_for_each_entry(connector, &mode_config->connector_list, head)
 56			radeon_connector_hotplug(connector);
 57	}
 58	/* Just fire off a uevent and let userspace tell us what to do */
 59	drm_helper_hpd_irq_event(dev);
 60}
 61
 62void radeon_driver_irq_preinstall_kms(struct drm_device *dev)
 63{
 64	struct radeon_device *rdev = dev->dev_private;
 65	unsigned i;
 66
 67	/* Disable *all* interrupts */
 68	for (i = 0; i < RADEON_NUM_RINGS; i++)
 69		rdev->irq.sw_int[i] = false;
 70	rdev->irq.gui_idle = false;
 71	for (i = 0; i < RADEON_MAX_HPD_PINS; i++)
 
 
 72		rdev->irq.hpd[i] = false;
 73	for (i = 0; i < RADEON_MAX_CRTCS; i++) {
 74		rdev->irq.crtc_vblank_int[i] = false;
 75		rdev->irq.pflip[i] = false;
 76		rdev->irq.afmt[i] = false;
 77	}
 78	radeon_irq_set(rdev);
 79	/* Clear bits */
 80	radeon_irq_process(rdev);
 81}
 82
 83int radeon_driver_irq_postinstall_kms(struct drm_device *dev)
 84{
 85	struct radeon_device *rdev = dev->dev_private;
 86	unsigned i;
 87
 88	dev->max_vblank_count = 0x001fffff;
 89	for (i = 0; i < RADEON_NUM_RINGS; i++)
 90		rdev->irq.sw_int[i] = true;
 91	radeon_irq_set(rdev);
 92	return 0;
 93}
 94
 95void radeon_driver_irq_uninstall_kms(struct drm_device *dev)
 96{
 97	struct radeon_device *rdev = dev->dev_private;
 98	unsigned i;
 99
100	if (rdev == NULL) {
101		return;
102	}
103	/* Disable *all* interrupts */
104	for (i = 0; i < RADEON_NUM_RINGS; i++)
105		rdev->irq.sw_int[i] = false;
106	rdev->irq.gui_idle = false;
107	for (i = 0; i < RADEON_MAX_HPD_PINS; i++)
 
 
108		rdev->irq.hpd[i] = false;
109	for (i = 0; i < RADEON_MAX_CRTCS; i++) {
110		rdev->irq.crtc_vblank_int[i] = false;
111		rdev->irq.pflip[i] = false;
112		rdev->irq.afmt[i] = false;
113	}
114	radeon_irq_set(rdev);
115}
116
117static bool radeon_msi_ok(struct radeon_device *rdev)
118{
119	/* RV370/RV380 was first asic with MSI support */
120	if (rdev->family < CHIP_RV380)
121		return false;
122
123	/* MSIs don't work on AGP */
124	if (rdev->flags & RADEON_IS_AGP)
125		return false;
126
127	/* force MSI on */
128	if (radeon_msi == 1)
129		return true;
130	else if (radeon_msi == 0)
131		return false;
132
133	/* Quirks */
134	/* HP RS690 only seems to work with MSIs. */
135	if ((rdev->pdev->device == 0x791f) &&
136	    (rdev->pdev->subsystem_vendor == 0x103c) &&
137	    (rdev->pdev->subsystem_device == 0x30c2))
138		return true;
139
140	/* Dell RS690 only seems to work with MSIs. */
141	if ((rdev->pdev->device == 0x791f) &&
142	    (rdev->pdev->subsystem_vendor == 0x1028) &&
143	    (rdev->pdev->subsystem_device == 0x01fc))
144		return true;
145
146	/* Dell RS690 only seems to work with MSIs. */
147	if ((rdev->pdev->device == 0x791f) &&
148	    (rdev->pdev->subsystem_vendor == 0x1028) &&
149	    (rdev->pdev->subsystem_device == 0x01fd))
150		return true;
151
152	/* RV515 seems to have MSI issues where it loses
153	 * MSI rearms occasionally. This leads to lockups and freezes.
154	 * disable it by default.
155	 */
156	if (rdev->family == CHIP_RV515)
157		return false;
158	if (rdev->flags & RADEON_IS_IGP) {
159		/* APUs work fine with MSIs */
160		if (rdev->family >= CHIP_PALM)
161			return true;
162		/* lots of IGPs have problems with MSIs */
163		return false;
164	}
165
166	return true;
167}
168
169int radeon_irq_kms_init(struct radeon_device *rdev)
170{
171	int i;
172	int r = 0;
173
174	INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
175	INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi);
176
177	spin_lock_init(&rdev->irq.sw_lock);
178	for (i = 0; i < rdev->num_crtc; i++)
179		spin_lock_init(&rdev->irq.pflip_lock[i]);
180	r = drm_vblank_init(rdev->ddev, rdev->num_crtc);
181	if (r) {
182		return r;
183	}
184	/* enable msi */
185	rdev->msi_enabled = 0;
186
187	if (radeon_msi_ok(rdev)) {
 
 
 
 
188		int ret = pci_enable_msi(rdev->pdev);
189		if (!ret) {
190			rdev->msi_enabled = 1;
191			dev_info(rdev->dev, "radeon: using MSI.\n");
192		}
193	}
194	rdev->irq.installed = true;
195	r = drm_irq_install(rdev->ddev);
196	if (r) {
197		rdev->irq.installed = false;
198		return r;
199	}
200	DRM_INFO("radeon: irq initialized.\n");
201	return 0;
202}
203
204void radeon_irq_kms_fini(struct radeon_device *rdev)
205{
206	drm_vblank_cleanup(rdev->ddev);
207	if (rdev->irq.installed) {
208		drm_irq_uninstall(rdev->ddev);
209		rdev->irq.installed = false;
210		if (rdev->msi_enabled)
211			pci_disable_msi(rdev->pdev);
212	}
213	flush_work_sync(&rdev->hotplug_work);
214}
215
216void radeon_irq_kms_sw_irq_get(struct radeon_device *rdev, int ring)
217{
218	unsigned long irqflags;
219
220	spin_lock_irqsave(&rdev->irq.sw_lock, irqflags);
221	if (rdev->ddev->irq_enabled && (++rdev->irq.sw_refcount[ring] == 1)) {
222		rdev->irq.sw_int[ring] = true;
223		radeon_irq_set(rdev);
224	}
225	spin_unlock_irqrestore(&rdev->irq.sw_lock, irqflags);
226}
227
228void radeon_irq_kms_sw_irq_put(struct radeon_device *rdev, int ring)
229{
230	unsigned long irqflags;
231
232	spin_lock_irqsave(&rdev->irq.sw_lock, irqflags);
233	BUG_ON(rdev->ddev->irq_enabled && rdev->irq.sw_refcount[ring] <= 0);
234	if (rdev->ddev->irq_enabled && (--rdev->irq.sw_refcount[ring] == 0)) {
235		rdev->irq.sw_int[ring] = false;
236		radeon_irq_set(rdev);
237	}
238	spin_unlock_irqrestore(&rdev->irq.sw_lock, irqflags);
239}
240
241void radeon_irq_kms_pflip_irq_get(struct radeon_device *rdev, int crtc)
242{
243	unsigned long irqflags;
244
245	if (crtc < 0 || crtc >= rdev->num_crtc)
246		return;
247
248	spin_lock_irqsave(&rdev->irq.pflip_lock[crtc], irqflags);
249	if (rdev->ddev->irq_enabled && (++rdev->irq.pflip_refcount[crtc] == 1)) {
250		rdev->irq.pflip[crtc] = true;
251		radeon_irq_set(rdev);
252	}
253	spin_unlock_irqrestore(&rdev->irq.pflip_lock[crtc], irqflags);
254}
255
256void radeon_irq_kms_pflip_irq_put(struct radeon_device *rdev, int crtc)
257{
258	unsigned long irqflags;
259
260	if (crtc < 0 || crtc >= rdev->num_crtc)
261		return;
262
263	spin_lock_irqsave(&rdev->irq.pflip_lock[crtc], irqflags);
264	BUG_ON(rdev->ddev->irq_enabled && rdev->irq.pflip_refcount[crtc] <= 0);
265	if (rdev->ddev->irq_enabled && (--rdev->irq.pflip_refcount[crtc] == 0)) {
266		rdev->irq.pflip[crtc] = false;
267		radeon_irq_set(rdev);
268	}
269	spin_unlock_irqrestore(&rdev->irq.pflip_lock[crtc], irqflags);
270}
271